diff --git a/drivers/scsi/lpfc/COPYING b/drivers/scsi/lpfc/COPYING new file mode 100644 index 000000000..1bcc46f53 --- /dev/null +++ b/drivers/scsi/lpfc/COPYING @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff --git a/drivers/scsi/lpfc/ChangeLog b/drivers/scsi/lpfc/ChangeLog new file mode 100644 index 000000000..d409d55d9 --- /dev/null +++ b/drivers/scsi/lpfc/ChangeLog @@ -0,0 +1,1624 @@ +Changes from 20131002 to 20131014 + + * Changed version number to 8.3.7.34 + * Fixed not processing task management IOCB response status + (149471) + * Fixed spinlock hang (149776) + * Fixed regression in the fcp_icmnd64 changes (149473) + * Fixed invalid Total_Data_Placed value received for els and ct + command responses (149471) + * Fixed invalid fcp_rsp lenght for FCP_ICMND (149473) + +Changes from 20130919 to 20131002 + + * Changed version number to 8.3.7.33 + * Fixed invalid mailbox timeouts (146132) + * Fixed spinlock inversion problem (148339) + +Changes from 20130822 to 20130919 + + * Changed version number to 8.3.7.32 + * Fixed support of kernels that no longer support the + initialization function macros + * Fix crash after xri limit is reached (145907) + * Fixed issue of task management commands having a fixed timeout + * Incorporated upstream patch "lseek(fd, n, SEEK_END) does *not* go + to eof - n" into lpfc driver + * Fixed inconsistent spin lock useage (146476) + * Fix driver's abort loop functionality to skip IOs already getting + aborted + * Fixed failure to allocate SCSI buffer on PPC64 platform for SLI4 + devices (146362) + * Fix WARN_ON when driver unloads (146328) + * Fix crash on driver load due to cpu affinity logic (144668) + * Avoided making pci bar ioremap call during dual-chute WQ/RQ pci + bar selection (146139) + +Changes from 20130814 to 20130822 + + * Changed version number to 8.3.7.31 + * Fixed driver iocbq structure's iocb_flag field running out of + space (145867) + * Fixed system crash on driver load due to using cpu affinity + without proper setup (144668) + +Changes from 20130801 to 20130814 + + * Changed version number to 8.3.7.30 + * Fixed logging format of setting driver sysfs attributes hard to + interpret (145397) + * Fixed back to back RSCNs discovery failure (140905) + * Fixed race condition between BSG I/O dispatch and timeout + handling (142743) + * Fixed function mode field defined too small for not recognizing + dual-chute mode (145031) + * Updated Copyright dates - reconsile with upstream + * Removed obsolete fcp_eq_count and fcp_wq_count driver attributes + +Changes from 20130725 to 20130801 + + * Changed version number to 8.3.7.29 + * Removed data counting (residual fcfi_parm) in the case of + misbehaving target (143476) + * Fixed mailbox memory leak (144016) + +Changes from 20130712 to 20130725 + + * Changed version number to 8.3.7.28 + * Fix ramdom errors using first burst (143435) + +Changes from 20130703 to 20130712 + + * Changed version number to 8.3.7.27 + * Fixed not able to log informational messages at early stage of + driver init time (142741) + * Fixed using unsafe linked list macro for walking and deleting + linked list (139545) + * Fix Initiator FirstBurst behavior (142153) + * Fixed the format of some log message fields (142334) + +Changes from 20130627 to 20130703 + + * Changed version number to 8.3.7.26 + * Fix Multipath hang for TURs with large timeouts (141052) + * Fixed regression driver build issue introduced by fix for incorrect + FCP Priority value. + * Fix driver's FirstBurst capability (142153) + * Fix for incorrect FCP Priority value detected on wire (142120) + +Changes from 20130617 to 20130627 + + * Changed version number to 8.3.7.25 + * Fixed not able to perform PCI function reset when board was not + in online mode (141906) + * Fixed failure in setting SLI3 board mode for performing certain + OCM commands (138124) + * Fixed SLI3 failing FCP write on check-condition no-sense with + residual zero (141400) + * Fixed support for 128 byte WQEs (141687) + * Fixed driver's setting of reserved bits in mailbox commands (125843) + * Fixed max value of lpfc_lun_queue_depth (141043) + * Fixed Receive Queue varied frame size handling (136867) + +Changes from 20130613 to 20130617 + + * Changed version number to 8.3.7.24 + * Fixed TUR not aborted by timeout (141052) + +Changes from 20130603 to 20130613 + + * Changed version number to 8.3.7.23 + * Fix to allow OCM to correctly display Service Processor and ULP FW + names on PPC (111718) + * Updated copyright dates + +Changes from 20130523 to 20130603 + + * Changed version number to 8.3.7.22 + * Fixed freeing of iocb when internal loopback times out (139995) + * Fixed crash when loopback is executed for sli4 adapters (139990) + * Reversed patches of SLI host handling FCF modified event to the + in-use FCF (122752) + +Changes from 20130508 to 20130523 + + * Changed version number to 8.3.7.21 + * Fixed issue mailbox wait routine failed to issue dump memory mbox + command (137589) + * Merged from upstream: Fixed typos in kernel messages (136212) + * Fixed system panic due to unsafe walking and deleting linked list + (139425) + * Fixed Makefile build issues introduced by support of a new OS kernel + * Fixed FCoE connection list record junk vlan identifier + stored/used/displayed (125900) + * Clarified the behavior of the lpfc_max_luns module parameter + (139188) + * Fix to allow OCM to report FEC status (137545) + * Fixed a missing return code in a logging message (138577) + * Fixed some logging message fields (138577) + +Changes from 20130425 to 20130508 + + * Changed version number to 8.3.7.20 + * Fixed list corruption when lpfc_drain_tx runs (138180) + * Fixed devloss timeout race condition caused null pointer + reference system crash (135839) + * Fixed SCSI target bus reset handlers not return error status due + to port timeout (135051) + * Fixed TUR not aborted by adding 2 seconds to mid-layer timeout + (124245) + * Fixed starting reference tag when calculating BG error (138001) + * Fixed inconsistent list removal causes crash (133672) + +Changes from 20130409 to 20130425 + + * Changed version number to 8.3.7.19 + * Fixed system panic during handling unsolicited receive buffer + error condition (137513) + * Fix BlockGuard error checking (124904) + * Fix driver build with di kernel (137148) + * Fixed crash during FCoE failover testing (137039) + * Fix lpfc_used_cpu to be more dynamic (136988) + +Changes from 20130327 to 20130409 + + * Changed version number to 8.3.7.17 + * Fixed driver handling of CLEAR_LA with NPIV enabled causing SID=0 + frames out (106135) + * Fixed lpfc build when wmb() is defined as mb() + * Reduced tmo value set to FLOGI WQE for quick recovery from FLOGI + sequence timeout (126169) + * Provided support for message logging when FLOGI completes with clean + address bit set to zero (136258) + * Fixed driver parameter lpfc_fcp_cpu_map = 0 (135548) + * Fixed build failures with irq_set_affinity_hint (135548) + * Fixed driver vector mapping to CPU affinity (135548) + * Fixed iocb flags not being reset for scsi commands (135965) + +Changes from 20130318 to 20130327 + + * Changed version number to 8.3.7.16 + * Fixed system panic during EEH recovery due to midlayer acting on + outstanding I/O (134408) + * Fixed not returning FAILED status when SCSI invoking host reset + handler failed (135051) + * Fixed bad book keeping in posting els sgls to port (135051) + * Fixed deadlock between hbalock and nlp_lock use (135524) + * Fixed BlockGuard to take advantage of rdprotect/wrprotect info + when available (124904) + +Changes from 20130304 to 20130318 + + * Changed version number to 8.3.7.15 + * Reduced spinlock contention on SCSI buffer list (134075) + +Changes from 20130221 to 20130304 + + * Changed version number to 8.3.7.14 + * Fixed crash when processing bsg's sg list with high memory pages + (126524) + +Changes from 20130207 to 20130221 + + * Changed version number to 8.3.7.13 + * Fix lpfc_fcp_look_ahead module parameter + * Fix driver issues with SCSI Host reset (126376) + * Provided support for logging doorbell information in dual-chute + WQ and RQ setup (126388) + * Fixed driver load issues on kernels that have disabled certain + T10-DIF APIs (126197) + * Fix driver issues with large s/g lists for BlockGuard (125839) + * Fix driver issues with large lpfc_sg_seg_cnt values (125839) + +Changes from 20130206 to 20130207 + + * Changed version number to 8.3.7.12 + * Fixed pt2pt and loop discovery problems on topology changes + (124392) + * Remove driver dependency on HZ (125653) + +Changes from 20130131 to 20130206 + + * Changed version number to 8.3.7.11 + * Fixed a race condition between SLI host and port failed FCF + rediscovery (125527) + * Fixed BlockGuard error reporting (124904) + * Fixed VPI allocation issues after firmware dump is performed + (124422) + +Changes from 20130116 to 20130131 + + * Changed version number to 8.3.7.10 + * Fixed potential mis-interpretation of READ_TOPOLOGY reserved + fields (106135) + * Fix default value for lpfc_enable_rrq (124850) + * Fixed circular locking dependency and inconsistent lock state + issues (124659) + * Fixed PT2PT bring up problem for FC SLI4 (124480) + +Changes from 20130111 to 20130116 + + * Changed version number to 8.3.7.9 + * Fixed OXID reuse issue (CR 124270) + * Fixed asynchronous FCF modified event to in-use FCF failure to + trigger recovery (CR 122752) + +Changes from 20121214 to 20130111 + + * Changed version number to 8.3.7.8 + * Fix potential NULL pointer dereference in lpfc_sli4_rq_put() + * Fixed deadlock condition in FCF round robin handling (123778) + * Fixed bsg timeout handling issues that would result in crashes + (123696) + * Fixed NMI watch dog panic's when resetting the hba (123383) + * Fixed degraded performance after cable pulls (123431) + * Provided support for change_queue_type method in + scsi_host_template (111959) + +Changes from 20121127 to 20121214 + + * Changed version number to 8.3.7.7 + * Fixed infinite loop in lpfc_sli4_fcf_rr_next_index_get (112709) + * Fixed system crash due to SLI Port provisioning of invalid + resource count (113184) + +Changes from 20121026 to 20121127 + + * Changed version number to 8.3.7.6 + * Fixed potential memory corruption bug + * Provide support for FCoE protocol dual-chute (ULP) operation + (110792) + * Fixed processing stale ndlp state when the node is marked for + deferred removal (111669) + * Fixed no-context ABTS received on unsolicited receive queue + failed with BA_RJT (111529) + * Removed use of NOP mailboxes for interrupt verification in + pci_probe_one_s4 (112375) + * Fixed exhausted retry for plogi to nameserver (109854) + * Fixed not properly handle ELS_REC received on the unsolicited + receive queue (111528) + * Provided support for change_queue_type method in + scsi_host_template (111959) + * Correct mask error for ct retry check + * Correct buffer length overrun for error messages + +Changes from 20121008 to 20121026 + + * Changed version number to 8.3.7.5 + * Reconcile spelling issues and whitespace fix with upstream + * Fixed setting sequential delivery bit in a service class that is + not valid (30847) + * Fix the value of DIF field in WQE (111168) + +Changes from 20120913 to 20121008 + + * Changed version number to 8.3.7.4 + * Fixed a bug when receiving Target Resets during bus reset function with FCP2 devices + * Fixed build issues from missing version.h include + * Fixed boot from san failure when SLI4 FC device presented on the + same PCI bus (107869) + * Fixed whitespace regression. + * Reconcile whitespace issues and includes with upstream + * Fixed not reporting logical link speed to SCSI midlayer when QoS + not on (109014) + +Changes from 20120910 to 20120913 + + * Changed version number to 8.3.7.3 + * Fix performance problem in pt2pt mode (108953) + * Fixed SCSI host create showing wrong link speed on SLI3 HBA ports + (93969) + +Changes from 20120801 to 20120910 + + * Changed version number to 8.3.7.2 + * Corrected text for misconfigured port messages (108240) + * Fixed not checking solicition in progress bit when verifying FCF + record for use (108550) + * Fixed kernel warning on spinlock usage on some distributions + (108430) + * Fixed PRLI not being retried if a LS_RJT with a reason (93956) + * Fixed SLES11-SP2 taking up to 60 second longer to boot with SLI4 + board installed (33385) + * Fix FCP2 Retries for non-r/w commands (108188) + * Fixed Linux generic firmware download on SLI4 devices with longer + module names (108080) + * Expand I/O channel support for large systems + * Fixed SLI4 running heavy IO with function reset on PPC induced + PCI bus EEH error (81900) + * Fix incorrect comment in T10 DIF attributes + * Fixed checking BMBX register for RDY bit before writing the first + address in (107229) + * Fix imax to dmult conversion for eq_create (107074) + * Fix null pointer error for piocbq + * Corrected handling of jumps to mempool_free to fix potential memory leak + * Fixed leaking memory from pci dma pool (106836) + +Changes from 20120725 to 20120801 + + * Changed version number to 8.3.7.1 + * Cast uint64_t variables to unsigned long long to fix compile + warnings + * Fix long division for 32 bit environments (106454) + * Fixed unnecessary SCSI device reset escalation due to LLD + handling of I/O abort (106432) + * Fix lpfc_use_msi=0 for INTX (106448) + * Logged XRI of the SCSI command to be aborted on abort handler + timeout (29251) + * Fix bug with driver logging too many fcp underrun messages + (106279) + +Changes from 20120723 to 20120725 + + * Changed version number to 8.3.7.0 + * Fix number of IO channels to match CPUs + * Fix duplicate functionality between idiag/queInfo and + dumpSLIqinfo + * Remove LINUX_VERSION_CODE ifdefs + * Change default value of lpfc_fcp_imax + * Change name of fcp_eq_count module parameter to fcp_io_channel + * Fixed queInfo to include queue stats + * Add lpfc_fcp_look_ahead module parameter + * Fix checking SLI rev lpfc_fcp_imax_store + * Make WQ distribution algorithm a module parameter + * Change naming convention for SLI4 Interrupt vector + * Change fcp_imax to be HBA centric + * Utilize all MSI-X vectors for FCP IO + * Remove lockless entry from scsi template + * Fix ABTS recovery to be FC spec compliant (75373) + +Changes from 20120716 to 20120723 + + * Changed version number to 8.3.5.82 + * Fix BlockGuard lpfc_printf_vlog messages (103707) + * Fix parameter field in CQE to mask for LOCAL_REJECT status + (93992) + * Fix Resource and Capacity Descriptors to support SLI-4 + interface change (96637) + +Changes from 20120629 to 20120716 + + * Changed version number to 8.3.5.81 + * Fixed incomplete list of SLI4 commands with extended 300 second + timeout value (96156) + * Fix switching ports on Fabric causing additional fc_host rport + entries (95843) + +Changes from 20120621 to 20120629 + + * Changed version number to 8.3.5.80 + * Fix discovery bug when swapping cables (95526) + * Revert unecessary code change (95526) + * Fixed kernel panic after scsi_eh escalation by checking the + proper return status (CR 129611) + * Fix conflicts in log message numbers + +Changes from 20120611 to 20120621 + + * Changed version number to 8.3.5.79 + * Fix driver not checking data transfered on write commands (CR + 127391) + * Fix bug with message 2520 appearing in the messages file (CR + 132548) + * Fix bug with rrq_pool not being destroyed during driver removal + (CR 132386) + +Changes from 20120525 to 20120611 + + * Changed version number to 8.3.5.78 + * Fix Driver not attaching to OCe14000 adapters + * Fix bug with driver not setting the diag set valid bit for + loopback testing (CR 130864) + * Fix bug with driver does not reporting misconfigured ports for + GM-LP-R (CR 131589) + +Changes from 20120524 to 20120525 + + * Changed version number to 8.3.5.77 + * Fix System Panic During IO Test using Medusa tool (CR 129611) + +Changes from 20120511 to 20120524 + + * Changed version number to 8.3.5.76 + * Fix fcp_imax module parameter to dynamically change FCP EQ delay + multiplier + * Fix successful aborts returning incorrect status (CR 131626) + * Fixed system held-up when performing resource provision through + same PCI function (CR 131421) + * Fix system hang due to bad protection module parameters (CR + 130769) + +Changes from 20120503 to 20120511 + + * Changed version number to 8.3.5.75 + * Fixed debug helper routine failed to dump CQ and EQ entries in + non-MSI-X mode (CR 130735) + +Changes from 20120427 to 20120503 + + * Changed version number to 8.3.5.74 + * Fixed system crash due to not providing SCSI error-handling host + reset handler (CR 130121) + * Fix bug with driver using the wrong xritag when sending an els + echo (CR 130019) + +Changes from 20120413 to 20120427 + + * Changed version number to 8.3.5.73 + * Debug helper utility routines for dumping various SLI4 queues (CR + 130735) + * Fix unsol abts xri lookup (CR 129215) + * Fixed issues with LPe16000 to LPe16000 discovery (CR 130446). + * Reregister VPI for SLI3 after cable moved to new Saturn port (CR + 129438) + * Fix driver crash during back-to-back ramp events (CR 128489) + +Changes from 20120403 to 20120413 + + * Changed version number to 8.3.5.72 + * Fix log message 2597 displayed when no error is detected (CR + 129185) + * Update Makefile and lpfc_attr.c to build for OL UEK R2 kernel + * Fixed FCP LOG for easier Finisar trace correlation (CR 130098) + * Fix kernel panic when going into to sleep state (CR 127161) + +Changes from 20120316 to 20120403 + + * Changed version number to 8.3.5.71 + * Fix error message displayed even when not an error (CR 129683) + * Fix Read Link status data (CR 129681) + * Fixed system panic due to midlayer abort and driver complete race + on SCSI cmd (CR 128422) + * Fix unable to create vports on FCoE SLI4 adapter (CR 129170) + * Fix the case where an array controller does not apply FCP + priority rules (CR 129626) + * Fix initiator sending flogi after acking flogi from target (CR + 128501) + +Changes from 20120302 to 20120316 + + * Changed version number to 8.3.5.70 + * Fix bug with driver not supporting the get controller attributes + command (CR 129259) + * Added support for handling SLI4-port XRI resource-provisioning + profile change (CR 127354) + * Add new BUILD_* variable to properly build for new UEK kernels, + rename old ones + +Changes from 20120217 to 20120302 + + * Changed version number to 8.3.5.69 + * Synch up with upstream driver sources. + * Upstream patch sync + * Change default DA_ID support from disabled to enabled (CR 126653) + * Fix bug with driver unload leaving a scsi host for a vport around + (CR 128762) + * Update copyright date for files modified in 2012 + * Fix bug with mailbox handling of REG_VFI and cable pull (CR + 127762) + * Enhance T10 DIF debugfs error injection (CR 123966) + +Changes from 20120210 to 20120217 + + * Changed version number to 8.3.5.68 + * Fix compilation errors on some kernels due to debugfs + variable definitions. + +Changes from 20120130 to 20120210 + + * Changed version number to 8.3.5.67 + * Used PCI configure space read to flush PCI function reset + register write (CR 128101) + * Update copyright date for files modified in 2012 + * Fixed system panic when extents enabled with large number of + small blocks (CR 128010) + * Fixed system panic during EEH recovery (CR 127062) + * Fix resource leak when acc fails for received plogi (CR 127847) + +Changes from 20120118 to 20120130 + + * Changed version number to 8.3.5.66 + * Fix SLI4 driver module load and unload test in a loop crashes + the system (CR 126397) + * Fix missing CVL event causing round-robin FCF failover process + to stop (CR 123367) + * Fix deadlock during adapter offline request (CR 127217) + * Fix same RPI registered multiple times after HBA reset (CR + 127176) + +Changes from 20120113 to 20120118 + + * Changed version number to 8.3.5.65 + * Fix driver handling of XRI Aborted CQE response (CR 127345) + * Fixed port and system failure in handling SLI4 FC port function + reset (CR 126551) + * Fix bug with driver not sending a LOGO with vport delete (CR + 126625) + +Changes from 20120106 to 20120113 + + * Changed version number to 8.3.5.64 + * Make BA_ACC work on a fully qualified exchange (CR 126289) + * Fix for SLI4 Port delivery for BLS ABORT ACC (CR 126289) + * Fix KERNEL allocation while lock held + * Incorrect usage of bghm for BlockGuard errors (CR 127022) + * Fix warning on i386 system (CR 132966) + * Fix ndlp nodelist not empty wait timeout during driver + unloading (CR 127052) + * Fix mailbox and vpi memory leaks (CR 126818) + +Changes from 20111223 to 20120106 + + * Changed version number to 8.3.5.63 + * Create character device to take a reference on the driver (CR + 126082) + * Fix for FDISC failures after firmware reset or link bounce (CR + 126779) + * Enhance debugfs for injecting T10 DIF errors (CR 123966) + * Fix SLI4 BlockGuard behavior when protection data is generated by + HBA (CR 121980) + +Changes from 20111216 to 20111223 + + * Changed version number to 8.3.5.62 + * Fix for driver using duplicate RPIs after 16Gb/s adapter + port reset (CR 126723) + * Fix discovery problem when in pt2pt (CR 126887) + * Fixed failure in handling large CQ/EQ identifiers in an IOV + environment (CR 126856) + * Fix Locking code raises IRQ twice + * Fix driver not returning when bad ndlp found in abts error event + handling (CR 126209) + * Added more driver logs in area of SLI4 port error attention and + reset recovery (CR 126813) + +Changes from 20111208 to 20111216 + + * Changed version number to 8.3.5.61 + * Fix bug with driver returning the wrong ndlp (CR 125743) + * Sync up with actual upstream lpfc driver code + * Added SLI4 16Gb FC Adapter support for T10 DIF / BlockGuard + (CR 121980) + * Merge from upstream: scsi: Fix up files implicitly depending on + module.h inclusion + * Fix driver behavior when receiving an ADISC (CR 126654) + * Fixed unbounded firmware revision string from port caused the + system panic (CR 126560) + * Fix bug with driver processing dump command type 4 using 16Gb FC + Adapter (CR 126406) + * Fix driver does not reset port when reset is needed during + fw_dump (CR 125807) + +Changes from 20111205 to 20111208 + + * Changed version number to 8.3.5.60 + * Fix ELS FDISC failing with local reject / invalid RPI (CR 126350) + * Changed SLI4 FC port internal loopback from outer serdes to inner + internal (CR 126409) + * Fix REG_RPI fails on SLI4 HBA putting NPort into NPR state (CR + 126230) + * Fix bug with driver processing an els command using 16Gb FC + Adapter (CR 126345) + +Changes from 20111201 to 20111205 + + * Changed version number to 8.3.5.59 + * Fix NMI seen due to CQE starvation (CR 126149) + * Fixed SLI4 FC port obtained link type and number dependent on + link connection (CR 126264) + * Fixed SLI4 FC port internal loopback without SFP and external + link/loopback plug (CR 125843) + * Fix driver incorrectly building fcpCdb during scsi command prep + (CR 126209) + +Changes from 20111118 to 20111201 + + * Changed version number to 8.3.5.58 + * Fixed FCP EQ memory check prevent initialize to single interrupt + vector case (CR 125832) + * Fixed SLI4 16Gbit FC port internal and external diagnostic + loopback tests (CR 125843) + * Fixed system panic during EEH recovery on SLI4 FC port (CR + 125832) + * Fix FLOGI fails with invalid RPI (0x04) after connecting to a + arbitrated loop (CR 126094) + * Fix ELS SCR failing with local reject / invalid RPI (CR 126070) + * Fix SLI4 port failures after firmware reset or dump (CR 125888) + * Fix port reset log messages indicate error when no error is seen + (CR 125989) + * Fixed an issue where HBQ buffers are uninitialized in the + base driver (CR 125663) + * Fixed missing shost lock protection on setting/clearing bit in + vport->fc_flag (CR 126002) + * Fixed missing hbalock protection on setting/clearing bit in + phba->link_flag (CR 125994) + * Fixed illegal state transition during driver unload (CR 124191) + * Fixed system crash on SLI4 FC port looopback diagnostic test with + large buffers (CR 124951) + * Fixed a potential error path that might try to free DMA memory + not allocated (CR 125766) + * Fixed SLI4 FC port Internal and External loopback diagnostic + tests (CR 124951) + +Changes from 20111114 to 20111118 + + * Changed version number to 8.3.5.57 + * Fix a crash while deleting 256 vports (CR 124996) + * Fix vport never finished discovery if switch runs out of + resources (CR 124996) + * Fix kernel build warnings (CR 125622) + * Fix kernel panic when putting board in offline state twice (CR + 125572) + * Fix memory leak when running hba resets to SLI-4 board (CR + 125124) + +Changes from 20111110 to 20111114 + + * Changed version number to 8.3.5.56 + * Fix driver message 3092 and 3116 to KERN_WARNING (CR 124768) + * Fix PCI read failure looks like a over temperature event (CR + 125403) + * Fixed driver event reporting to mgmt on error attention due to + forced dump (CR 122986) + * Fix not displaying firmware rev for BE UCNA boards (CR 125369) + * Fixed ABTS failure logic not rediscovering targets (CR 124578) + * Fix bug with driver not byte swapping extended mailbox data (CR + 125081) + +Changes from 20111103 to 20111110 + + * Changed version number to 8.3.5.55 + * Fix premature ndlp cleanup after second target LOGO (CR 123924) + * Fix Link pull causes I/O failures (CR 124668) + * Add loop support for sli4 fc (CR 124721) + +Changes from 20111017 to 20111103 + + * Changed version number to 8.3.5.54 + * Fixed OCM failing COMN_READ_OBJECT and COMN_WRITE_OBJECT mailbox + pass-through (CR 124771) + * No longer read fcoe parameters if board is not fcoe (CR 124731) + * Fix bug with driver passing a wrong count value (CR 122550) + * Added restore state and error log when sysfs board_mode attribute + access failed (CR 124158) + * Fixed a typo in two of the log messages just introduced (CR + 124466) + * Added support for SLI4_CONFIG non-embedded + COMN_GET_CNTL_ADDL_ATTR pass-through (CR 124466) + * Added support for SLI4 FC port persistent linkdown through config + region 23 (CR 124534) + * Fix for ABTS. Do not free original IOCB whenever ABTS fails (CR + 115829) + * Fixed Linux driver inconsistency in reporting FC host port-state + through OCM (CR 120018) + * Return an error if the mbox sysfs is called (CR 124210) + * Fix firmware upgrade attempt on unsupported adapter (CR 124406) + * Fix incomplete message number 2889 (CR 124385) + * Fix system crash when Lancer fails to initialize (CR 124390) + +Changes from 20111007 to 20111017 + + * Changed version number to 8.3.5.53 + * Merged non-functional updates from the upstream driver sources. + * Fix virtual fabrics bit set in FLOGI incorrectly (CR 124339) + * Fix bug with driver not returning extended mailbox data (CR + 122523) + * Fix unsupported link speed accepted by SLI4 port (CR 124185 + 124122) + * Incremented minor management version to reflect additional + "protocol" sysfs attribute (CR 124102) + * Modify WQ handling to use entry_repost (CR 123981) + * Moved link type definitions to apply to all driver streams + (CR 124102) + * Added a sysfs attribute "protocol" to report SLI4 port link + protocol type (CR 124102) + * Added SLI4 INTF_TYPE and SLI_FAMILY as sub-field to the fwrev + sysfs attribute (CR 124103) + +Changes from 20110927 to 20111007 + + * Changed version number to 8.3.5.52 + * Added structure to support T10 DIF in SLI4 (CR 121980) + * Fix performance slowed due to too many register accesses (CR + 123981) + * Fixed a warning when converting from simple_strtoul to + strict_strtoul + * Add Initial code to inject T10 DIF errors (CR 123966) + * Fixed a possible driver crash when cfg_fcp_eq_count is zero (CR + 123879) + * Fixed non-embedded COMMON_GET_CNTL_ATTR mbox command failed with + status 0x4 (CR 123792) + +Changes from 20110915 to 20110927 + + * Changed version number to 8.3.5.51 + * Fixed null pointer dereference after clearing FCP policy rules + (CR 123378) + * Changed the way of SLI4 device detecting physical port name (CR + 122006) + * Fixed FCP policy exchange management rule parsing (CR 123362) + * Add new check to lpfc_decode_firmware_rev to handle releases that + have an 'X' (CR 122167) + * Fixed RPI leaks in ELS protocol handling (CR 123150) + * Fix kernel crash during boot with SLI4 card installed (CR 122270) + * Fixed NPIV FDISC failure on SLI4 if-type 2 ports (CR 122788) + * Fixed driver failed to follow IP reset procedure in SLI4 error + attention handler (CR 122932 123052) + +Changes from 20110906 to 20110915 + + * Changed version number to 8.3.5.50 + * Fixed warnings with OEL5 and OEL6 kernel builds (CR 122844) + * Fix sysfs lists fabric name for port that has been disconnected + from fabric (CR 93875 122918) + * Add FCP policy exchange management (CR 122912) + * Changed the timeout to 300 seconds for SLI_CONFIG (0x9B) mailbox + command (CR 122650) + * Fixed fcp underrun reporting + +Changes from 20110825 to 20110906 + + * Changed version number to 8.3.5.49 + * Fixed a driver handling IP reset issue when PCI read return error + (CR 121797) + * Fixed casting problem in calculating tx_words statistics + * Added proper error code return for libdfc calling API to make + proper decisions + * Fix sli4 mailbox status code. Management software has + dependencies + +Changes from 20110819 to 20110825 + + * Changed version number to 8.3.5.48 + * Fix compiler warning due to uninitialized local variable + +Changes from 20110711 to 20110819 + + * Changed version number to 8.3.5.47 + * Fix bus reset handler fails with bad failure code (CR 121856) + * Made proper error code return for libdfc calling API to make + proper decisions + * Made error log include PCI BAR bitmap from kernel when enable PCI + device failed + * Fixed sysfs API mismatch for building against SLES11 SP2 beta + kernel + * Fixed scsi midlayer queuecommand API mismatch for SLES11 SP2 beta + kernel + * Fixed ctlreg write bug not checking key string and limiting bytes + to write (CR 121771) + * Fix default adapter name for the OCe15100 + * Fixed incomplete scsi messages displayed + * Fix cable pull failure on interface type 2 SLI-4 adapters + * Fix enable_bg config parameter for SLI4 + * Fixed not able to perform firmware reset through sysfs board_mode + attribute (CR 121468) + * Fixed not recovering SLI port in handling error attention with RN + bit set + * Fixed two crash cases when unsolicted ELS ECHO_CMD is received + * Fix direct connect does not come up for SLI4 FC ports + * Fixed long wait when firmware reset to a SLI port without + required privilege + * Fix request firmware support for little endian systems + * Fix driver firmware update to match new firmware image format + * Fixed SLI4 device firmware reset with SR-IOV virtual functions + * Fix SLI4 CT handling for sequences > 4K + * Fixed handling of unsolicited frames for vports + * Fixed handling of CVL for vports + * Fixed crash when aborting els IOs + * Fix up CT and oxid/rxid for unsol rcv frames + * Fixed mailbox double free panic + * Added fcf priority record selection for fcf failover + * Fixed compiler warning for putting large amount of memory on + stack + +Changes from 20110606 to 20110711 + + * Changed version number to 8.3.5.46 + * Fixed driver build not building in debugfs even if kernel + CONFIG_DEBUG_FS=y is set + * Fix issue where the FC/FCoE Async Receive CQE did not scale for + 16G FC adapters + * FLOGI payload has Multiple N_port_ID set when lpfc_enable_npiv + clear (CR 119918) + * Removed unused argument passed to the lpfc_bsg_diag_mode_enter + routine + * Fixed new ASIC device-mgmt BSG pass-through failed multi-buffer + fw download (CR 120183) + * Add sysfs logging when writeable parameters are changed (CR + 120132) + * Used PCI config space capability for sysfs get PF supported SR- + IOV number of VFs + * Added wait for SLI port status register for readyness following + firmware reset + * iDiag added SLI4 device PCI BAR memory mapped reigster access + methods (CR 114450) + * Consolidated duplicating macro definitions + * Fixed failure to enable PCIe AER prevent driver initialize and + attach to device (CR 119658) + * Modified log messages for T10-PI processing + * iDiag fixed mailbox capture and dump overlapping bitmap macro + definition + +Changes from 20110519 to 20110606 + + * Changed version number to 8.3.5.44_x1 + * iDiag extended debugfs setting up inline mailbox capture and dump + capability + * Fix bug in BlockGuard error path handling + * Fix EEH recovery so state is saved after every PCI reset for SLI4 + * Fix FC Port swap on SLI3 adapters (CR 118947) + * Fixed Virtual link loss during Face plate failover test (CR + 118954) + * Relaxed the driver enforcement of extended mailbox command with + 2KB limitation (CR 118899) + * Fix vpi initialization in lpfc_init_vfi + * Turn on MSI-X by default + * Resolved T10-PI implementation issues + * Fixed failure to show 16 Gbit from FC host supported_speeds sysfs + entry (CR 118863) + * Added setting specific pf_number in GET_PROFILE_CONFIG to get + maximum virtfn (CR 118717) + * Added driver capability of resetting new ASIC firmware and device + from sysfs entry (CR 118735) + * Add firmware upgrade code to driver + * Added capability of inducing New ASIC firmware dump obj file to + flash filesystem (CR 118716) + * Added 100ms delay before driver action following IF_TYPE_2 + function reset + * Added Linux driver SR-IOV management support for both SLI3 and + SLI4 devices + * Fragment ELS and SCSI SGE lists based on Extent regions + * Remove GET_ALLOCATED extent count response work-around (CR + 117595) + * Fixed potential missed SLI4 device initialization failure + conditions + * Fixed build warning on SLES11-SP1 + * Fixed Back to back Flogis sent without a logo (CR 118272) + * Add model names for new hardware + * Fix bug with lpfc driver not updating the wwnn and wwpn after a + name change (CR 117517) + * New WWNs written successfully + * WWNs restored successfully + * Set the maximum SGE size to 0x80000000 when HBA does not have any + restriction + * Added New ASIC device link diagonstic test and link diagnostic + loopback test support (CR 117009) + * Fixed mix-and-match backward compability with the new ASIC + device management (CR 117009) + * Fix SLI3 and non-NPIV crashes with new extent code + * Fixed BSG failure in handing pass-through mailbox with multiple + external buffers (CR 117009) + * Fix CT command never completing on Big Endian system + * Refactor lpfc_sli4_alloc_extent some more + * Restore SLI4_PARAMETER mailbox can fail as nonerror functionality + * Do not post RPI Headers to SLI4 port that support extents + * Fixed a race condition where the driver may invalidate an + RPI of an incoming PLOGI before responding to it (CR 117746) + * Refactor code in lpfc_sli4_alloc_extent + * Restore removed branch + * Fix port capabilities and get parameters mailbox calls + * Fix SLI2 crashes with new extent code + * Fixed EEH failure on PPC-P7 due to the platform required PCI + fundamental reset (CR 116845) + * Fixed incorrect size set into the sysfs binary file access + interface (CR 116845) + * Brought debugfs accessing New ASIC extents information into the + iDiag framework + * Fix mailbox processing to not overwrite mailbox status codes + * Changed enumerate members starting from none zero value (CR + 117009) + * Remove driver workaround for COMMON_ALLOC_RESOURCE_EXTENTS + endianess issue + * Fix lpfc_printf_log message numbers + * Implement debugfs support for resource extents + * iDiag method for read write bitset bitclear access to new ASIC + control registers (CR 114450) + * Call correct mailbox cleanup routine after extents are allocated + * Implement extent block list member cleanup and free memory + resources + * Fix memory leak in extent block lists + * Modified variables for XRIs to be unsigned variable + +Changes from 20110412 to 20110415 + + * Changed version number to 8.3.5.41_x1 + * Fix crash in rpi clean when driver load fails + * iDiag method for dumping mailbox command from SLI4 issue + mailbox command routine (CR 114450) + * Implement support for nonembedded Extent mailbox IOCTLs. + * Update package README files to reflect first Phase4 kernel + and architecture support. + * Fixed race condition between driver multi-buffer seesion + reset and bsg job done. + * Fix Port Error detected during POST. + * Added protection on new ASIC specific mbox cmd passed to + other ASIC interface type. + * Added protection on non-embedded mailbox command for number + of external buffers. + * Implement extent block list member cleanup and free memory + resources. + * Fix memory leak in extent block lists. + * Modified variables for XRIs to be unsigned variable. + * Fix crash in rpi clean when driver load fails. + * Fixed race condition between driver multi-buffer seesion + reset and bsg job done (CR 116491) + +Changes from 20110329 to 20110412 + + * Changed version number to 8.3.5.41 + * Fixed mask size for the wq_id mask + * Fixed mailbox command completion invoke BSG job_done while + holding spinlock (CR 117009) + * Fixed double byte swap on received RRQ + * Fixed no BSG data transfer size protection in mailbox command + pass-through path (CR 117007) + * Make adjustments for systems with Page Size Larger than 4k + * Fixed new ASIC mbox queue id collision with work queue id in + debugfs queue access (CR 116937) + * Fixed bug in BSG pass-through mailbox size check to non-embedded + external buffer + +Changes from 20110315 to 20110329 + + * Changed version number to 8.3.5.40 + * Fixed ISO C90 build error + * Fix FCFI incorrect on received unsolicited frames (CR 115710) + * Add LOG_ELS message to NPIV LOGO + * Fixed Vports not sending FDISC after lips (CR 116365) + * Fix bug with lpfc driver causing a system crash during driver + unload (CR 116071) + * Added user-kernel shared sli-config mailbox header for new ASIC + device management + +Changes from 20110314 to 20110315 + + * Changed version number to 8.3.5.39 + * Added iDiag driver support for debugfs SLI4 device doorbell + register access methods (CR 114450) + * Fixed driver sending FLOGI to a disconnected FCF (CR 115785) + * Fix RQ_CREATE version 1 fails (CR 115564) + * Fix FCFI incorrect on received unsolicited frames (CR 115710) + * Added iDiag driver support for debugfs SLI4 device display + host/port index in decimal (CR 114450) + * Do not limit RPI Count to a minimum of 64 + * Do not override CT field in issue_els_flogi for SLI4 IF type 2 + * Add Temporary RPI field to the ELS request WQE + * Allow SLI4 with FCOE_MODE not set for new SLI4 FC adapters + * Restrict driver to look at BAR2 or BAR4 only for if_type 0 + * Added iDiag driver support for debugfs SLI4 device queue entry + access methods (CR 114450) + +Changes from 20110301 to 20110314 + + * Changed version number to 8.3.5.38 + * Update copyright date for all changed files + * Merge from upstream: block target when port queuing + limit is hit + * Merge from upstream: force retry in queuecommand when port is + transitioning + * Fix bug with incorrect BLS Response to BLS Abort (CR 114886) + +Changes from 20110215 to 20110301 + + * Changed version number to 8.3.5.37 + * Fixed crash when mailbox commands timeout through BSG (CR + 115249) + * Modified existing driver code to handle PCI Link drop detection + failure (CR 110174) + * Fixed issue when BDEs cross 4K boundary + * Fixed an issue where OneConnect UCNA on PPC architecture was + unable to login into Fabric + * Fix debugfs build error caused by undefined macro + * Add selective reset jump table entry + +Changes from 20110131 to 20110215 + + * Changed version number to 8.3.5.36 + * Add new Queue create Mailbox versions for new ASIC + * Place LPFC driver module parameters to + /sys/module//parameters (CR 26210 114646) + * Performance Hints support + * Add new driver interfaces for encryption products (CR 114577) + * iDiag driver support debugfs queue information get (CR 114450) + * iDiag driver support debugfs PCI config space register bits + set/clear methods (CR 114450) + * iDiag driver support debugfs framework and read/write PCI config + space registers (CR 114450) + +Changes from 20110118 to 20110131 + + * Changed version number to 8.3.5.35 + * Defined the right macro in the GNUmakefile for enabling lpfc + driver debugfs + * Fix rrq cleanup for vport delete (CR 113341) + * Configuration parameter lpfc_suppress_link_up is ignored for + SLI-4 + * LOGO completion routine must invalidate both RPI and D_ID (CR + 113738) + * Do not take lock when clearing rrq active (CR 113252) + * Save IRQ level when taking host_lock in findnode_did + * Fixed hang in lpfc_get_scsi_buf_s4 (CR 113960) + * Fix xri lookup for received rrq + * Fixed missed setting of RRQ active for target aborted IOs + * Modified lpfc_delay_discovery implementation + +Changes from 20110107 to 20110118 + + * Changed version number to 8.3.5.34 + * Fixed fdisc sent with invalid VPI (CR 111517) + * Print something out if the link_speed is not supported by this + adapter (CR 86577) + * Fixed UE error reported by OneConnect UCNA BE2 hba with + f/w 2.702.542.0 during reboot (CR 113607) + +Changes from 20101222 to 20110107 + + * Changed version number to 8.3.5.33 + * Added support for clean address bit (CR 113373) + * Fixed XRI reuse issue (CR 111518) + +Changes from 20101216 to 20101222 + + * Changed version number to 8.3.5.32 + * Unreg login when PLOGI received from logged in port (CR 113197) + * Fixed crashes for NULL vport dereference (CR 112630) + +Changes from 20101214 to 20101216 + + * Changed version number to 8.3.5.31 + * Fix for kmalloc failures in lpfc_workq_post_event (CR 112404) + * Adjust payload_length and request_length for sli4_config mailbox + commands + +Changes from 20101129 to 20101214 + + * Changed version number to 8.3.5.30 + * Turned parity and serr bits back on after performing sli4 board + reset PCI access + * Use VPI for ALL ELS commands and allocate RPIs at node creation + * Correct bit-definitions in SLI4 data structures + +Changes from 20101118 to 20101129 + + * Changed version number to 8.3.5.29 + * Implement new SLI4 initialization procedures based on if_type + * Implement the FC and SLI async event handlers + * Fixed management command context setting + * Fixed panic in the __lpfc_sli_get_sglq + +Changes from 20101111 to 20101118 + + * Changed version number to 8.3.5.28 + * Set heartbeat timer off by default + * Added support for ELS RRQ command (CR 110683) + * Init VFI and VPI for the physical port (Lancer SLI4 FC Support) + +Changes from 20101103 to 20101111 + + * Changed version number to 8.3.5.27 + * Fixed a NULL pointer dereference duing memory allocation failure + (CR 111997) + * Modified the return status of unsupport ELS commands + * Implement READ_TOPOLOGY mailbox command and add new speed definition + * Implement doorbell register changes for new hardware support + * Fix bug with remote SLI4 firmware download data not being + transmitted (CR 110883) + * Implement the new SLI 4 SLI_INTF register definitions + * Added PCI ID definitions for new hardware support + * Fix for failure to log into FDMI_DID after link bounce (CR + 110885) + * Updated driver to handle CVL after Nameserver PLOGI timeouts (CR + 111516) + * Prep for fc host dev loss tmo support + * Cleanup mailbox commands in mboxq_cmpl when CVL is received (CR + 111515) + * Add new SLI4 WQE support + +Changes from 20101006 to 20101103 + + * Changed version number to 8.3.5.26 + * Prevent lock_irqsave from being called twice in a row + * Fix locking issue for security mailbox commands + * Fix regression error for handling SLI4 unsolicted ELS. Read + Timeout Value (RTV) (CR 110683) + * Properly handle devloss timeout during various phases of FIP + engine state transactions (CR 109955) + * Abort all I/Os and wait XRI exchange busy complete before + function reset ioctl in SLI4 driver unload (CR 110980) + * Fix regression error for handling ECHO response support + (CR 110683) + * Fix regression error for handling SLI4 unsolicted ELS. Read + Link Error Status Block (RLS) (CR 110683) + * Fix internal loopback causing kernel panic (CR 110438) + * Fixed crashes for NULL pnode dereference (CR 111422) + +Changes from 20100928 to 20101006 + + * Changed version number to 8.3.5.25 + * Fixed a race condition that can cause driver to send FDISC to + un-initialized VPI (CR 111250) + * Fix mailbox handling for UNREG_RPI_ALL case (CR 111249) + +Changes from 20100910 to 20100928 + + * Changed version number to 8.3.5.24 + * Used PCI function reset ioctl mbox command to clean up CNA during + driver unload (CR 110521) + * Fixed crashes for BUG_ONs hit in the lpfc_abort_handler (CR + 110994) + * Fail I/O when adapter detects a lost frame and target reports a + check condition (CR 110825) + * Fixed abort WQEs for FIP frames + +Changes from 20100901 to 20100910 + + * Changed version number to 8.3.5.23 + * Added unreg all rpi mailbox command before unreg vpi + * Make all error values negative (CR 99986) + * Clean up duplicate code in lpfc_els_retry + * Fixed circular spinlock dependency between low-level driver and + SCSI midlayer (CR 110305) + +Changes from 20100824 to 20100901 + + * Changed version number to 8.3.5.22 + * Fixed FC-AL bit set issue in FLOGI rejected by FC swich in NPV + setup (CR 110237) + * Fixed cases of skipping possible roundrobin failover of multiple + eligible FCFs (CR 110048) + * Fixed driver not able to unregister unused FCF upon devloss + timeout to all nodes (CR 109954) + * Fix bug with external loopback testing not becoming ready (CR + 109853) + * Fixed heartbeat timeout during controller pause test + +Changes from 20100811 to 20100824 + + * Changed version number to 8.3.5.21 + * Added support for OneSecure firmware download authentication and + SLI authentication (CR 106981) + * Add support for bsg MBX_SLI4_CONFIG (CR 107295) + * Remove owner field from attribute initialization + * Replaced some spin_lock_irqsave with spin_lock_irq + * Fixed lpfc_initial_flogi not returning failure in one failure + condition + * Fixed stray state update in case a new FCF matched in-use FCF + * Treated firmware matching FCF property with different index as + error condition + +Changes from 20100730 to 20100811 + + * Changed version number to 8.3.5.20 + * Move Unload flag earlier in vport delete (CR 103830) + * Fix for IOCB leak on FDISC completion (CR 106902) + * Start looking at the return code for fc_block_scsi_eh + * Call the lpfc_drain_txq only for SLI4 hba (CR 105946) + +Changes from 20100721 to 20100730 + + * Changed version number to 8.3.5.19 + * Remove whitespace at end of line + * Change log message 0318 from an error to a warning as it is not + an error + * Add Security Crypto support to CONFIG_PORT mailbox command + * Switch call from memcpy_toio to __write32_copy to prevent + unaligned 64 bit copy + * Fix nodelist not empty message on console after rmmod (CR 105401) + * Fix failure to roundrobin on all available FCFs when FLOGI to + in-use FCF rejected by switch (CR 105402) + * Fixed heartbeat timeout during fabric reconfiguration + +Changes from 20100709 to 20100721 + + * Changed version number to 8.3.5.18 + * Fixed failure to recover from back-to-back Clear Virtual Link + with a single FCF (CR 104974) + * Clear VFI_REGISTERED flag when UNREG_VFI completes + * Ignore the failure of REG_VPI mailbox with UPD bit set on older + set on older OneConnect firmware (CR 104912) + * Use active ndlp for ct response after cable swap (CR 104032) + * Properly set ndlp after cable swap (CR 104706) + * Add support for UPD bit of REG_VPI mailbox command (CR + 104912) + * Properly send ct response data with sli4 (CR 103765) + +Changes from 20100707 to 20100709 + + * Changed version number to 8.3.5.17 + * Fix endian conversion for BlockGuard in IOCB response + * Fix driver discovery issue where driver is unable to + discover a target after Eveready back link bounce test (CR + 104654) + +Changes from 20100625 to 20100707 + + * Changed version number to 8.3.5.16 + * Fixed BlockGuard endian conversion problem for supporting PowerPC + EEH + * Fixed VLAN ID 0xFFF set to reg_fcfi mailbox command on FCF empty + FCF VLAN bitmap (CR 104503) + +Changes from 20100608 to 20100625 + + * Changed version number to 8.3.5.15 + * Fix race condition causing FLOGI issued from dual processes + (CR 104288) + * Fix bug with ct response data not being sent with sli4 (CR + 103765) + * Fix RoundRobin FCF failover due to mis-interpretation of kernel + find_next_bit (CR 103435) + * Enhance round-robin FCF failover algorithm to re-start on new + FCF async event + * Clear Ignore Reg Login Flag when purging mailbox queue (CR + 104131) + * Fix for ELS commands stuck on txq (CR 103535) + * Add target queuedepth module parameter + * Fix bug with unsolicited CT event command not setting a flag (CR + 103648) + +Changes from 20100511 to 20100608 + + * Changed version number to 8.3.5.14 + * Fix LPFC_READ_REV mailbox command for BE + * Added driver Advanced Error Reporting (AER) support for SLI4 + devices + * Fixed FCF discovery failure after swapping FCoE port on + Brocade8000 FCoE switch (CR 102947) + * Fix RPI leak after a VFC shut/noshut storm (CR 102507) + * Allow enabling MSI-X interrupt with fewer vectors than requested + on SLI4 device + * Removed NOOP condition checking logic + * Prevent point to point discovery on a FCoE UCNA (CR 102844) + * Prevent unregistring of unused FCF when FLOGI is pending (CR + 102642) + * Restrict scsi buffer allocation (CR 102643) + * Fixed accounting of allocated SCSI buffers when post sgl fail (CR + 102644) + +Changes from 20100504 to 20100511 + + * Changed version number to 8.3.5.13 + * Remove module ref counting for active bsg requests + * Add PCI-ID for Gb PCIe Shared I/O Fibre Channel Adapter + * Only send ADISCs to Targets (CR 101933) + * Fix memory leak (CR 102354) + * Add support for SLER errors + * Fix SLI4 RPI leaks (CR 102369) + * Change default FCF max receive size (CR 102087) + * Remove unused Interrupt Notification Block Code + * Fix lpfc_sli_issue_wait call to put iocb on txcmpq that should + have been removed + * Fixed Illegal State Transition (CR 10202) + * Additional check-in for high vport fix (CR 99636) + +Changes from 20100429 to 20100504 + + * Changed version number to 8.3.5.12 + * Check whether index is within bounds before testing vport + * Change positive error return into negative + * Fixed Illegal State Transition after devloss tmo (CR 102025) + * Fixed Illegal State Transition (CR 10202) + * Fixed heartbeat timeout failure (CR 10142) + +Changes from 20100427 to 20100429 + + * Changed version number to 8.3.5.11 + * Fix bug with dma maps on nested scsi objects (CR 101174, 101425) + +Changes from 20100407 to 20100427 + + * Changed version number to 8.3.5.10 + * Add module ref counting to prevent module removal with active bsg + requests (CR 101863) + * Fix swapping target's FC ports caused I/O failure due to target + rejecting PLOGI (CR 100464) + * Reduce hba_queue_depth of SLI4 HBAs to account for XRIs reserved + for ELS commands + * Fixed hang on hba resets (CR 100032) + +Changes from 20100311 to 20100407 + + * Changed version number to 8.3.5.9 + * Fix for lpfc_get_hba_info to return correct value for max vpi + count + * Fix misspelled variable name in BSG interface API + * Add missing management support for MBX_READ_EVENT_LOG + * Check if mailbox command succeeded before copying data + * Make sure driver sets the "FCP Initiator" flag for remote + initiator ports (CR 100554) + * Add checks for lpfc_mbuf_alloc failure and sli4 dump zero bde + size + * Reset HBA when UNREG_VPI fail with busy status (CR 100218) + * Prevent failure of unreg_vpi mailbox command (CR 100219) + * Add additional warning message and refuse a mailbox command if + mgmt is blocked + * Add support for missing BSG mailbox commands dump, update cfg + and event log status + * Fix management regression bug with BSG BIU mailbox command not + copying application data + * Fixed hang on link transitions (CR 99675) + * Change mailbox commands to use SLI4 mailbox size instead of + PAGE_SIZE + * Fix UE and other issues seen after HBA resets with I/O (CR 97910) + * Fix crash with els reject data being formed (CR 99991) + * Rework the logical link speed (CR 99148 99149) + * Add ratov and edtov to the reg_vfi + * Enable required NPIV by default + * Fix crash while doing IO to a hornet + * Fix functionality regression for new PDE syle for BlockGuard + * Prevent log message 1801 during vport delete + * Fix functionality regression logical link speed event (CR 99148 + 99149) + * Fix hang on ia64 systems + +Changes from 20100226 to 20100311 + + * Changed version number to 8.3.5.7 + * Fix bug with copy in extended data to the extended buffer + * Add support for extended mailbox commands + * Enable NPIV by default + * Separate logging New FCF Found and FCF Parameter Modified + messages + * Fix devloss timeout running Hazard with AER error injection every + 30-60 seconds (CR 97468) + * Fix driver issue where the driver is unable to discover the + paths of luns on physical port of legacy adapter after uplink + failover on VC-FC module (CR 99120) + * Fix sli4 params read + * Add support for PCI loopback testing + * Made the FCF related informational log message only logged to + FCoE devices + * Made fast FCF failover randomly choose from eligible FCF records + with equal probability + * Fix Big Endian sli4 support + +Changes from 20100212 to 20100226 + + * Changed version number to 8.3.5.6 + * Added round robin FCF failover on initial or FCF rediscovery + FLOGI failure + * Fixed issue where the driver was unable to discover the paths of + vport luns on HBAs after uplink failover (CR 99070) + * Changed magic numbers to manifests for suppress_link_up param + * Remove unused variable from lpfc_nodev_tmo_show + * Added CEE bridge chip management support + * LPSe12002-ML1-E EmulexSecure Fibre Channel Adapter changes for + the encryption IOCB special handling + * Add logging messages for critical errors (CR 98726) + * Fixed not clearing LPFC_DRIVER_ABORTED bit in aborted FCP + cmdiocb->iocb_flag + * Removed fast FCF failover fabric name matching to allow failover + to any fit FCF + * Fixed SGL leak when XB bit is set (CR 98736) + * Added fast FCF failover in response to FCF DEAD event on current + FCF record + * Made driver SLI4 reporting ulpWord[4] status on aborted iocb same + as SLI3 (CR 98963) + * Fixed memory allocation failure in the read_sparam mailbox + handling (CR 98738) + * Fixed memory allocation issue in lpfc_config_port_post (CR 98739) + * Fixed vport discovery failure after CVL handling + * Fixed NULL pointer dereference when kernel is out of memory (CR + 98587) + +Changes from 20100202 to 20100212 + + * Changed version number to 8.3.5.5 + * Relax Event Queue field checking to allow non-zero minor codes + * Complete fix for vport->fc_flag set outside of shost host_lock + * Implement the PORT_CAPABITIES mailbox command + * Use asynchronous mailbox command for requesting FCF recovery + * LPSe12002-ML1-E EmulexSecure Fibre Channel Adapter changes for + delayed link up and fix a missing jump table initialization + * Fixed tab indent problem from previous commit + * Corrected comment to reflect lpfc_suppress_link_up instead of + lpfc_init_link + * Add Fast FCF failover support + * Change sysfs parameter macros to be uint instead of int (CR + 98283) + * Add support for new SLI features + * Added init_vpi mailbox command before re-registering VPI + * Add support for PCI BAR region 0 if BAR0 is a 64 bit register + * Call pci_save_state() after pci_restore_state() call to cope with + kernel change + +Changes from 20100112 to 20100202 + + * Changed version number to 8.3.5.4 + * Remove DHCHAP support + r7328) + * Fix bug with bsg issue mbox not handling a busy mailbox status + * Submit abort WQE to same work queue as the command WQE + * Add missing function comments, fix comment errors + * Add missing functionality LPFC_BSG_VENDOR_GET_MGMT_REV + * Add missing functionality LPFC_BSG_VENDOR_MBOX + * Add timeout handler for EVT jobs, goes with r7236 + * Add missing functionality LPFC_BSG_VENDOR_DIAG_MODE, + LPFC_BSG_VENDOR_DIAG_TEST + * Fix bug with mgmt response restting cmdiocbq for checkin r7235 + * Add missing functionality LPFC_BSG_VENDOR_SEND_MGMT_RESP + * Modify FC_BSG_RPT_ELS to operate asynchronously + * Fix bug with kzmalloc being called with ct_ev_lock held + * Falcon changes for IOCB command define values + * Modify LPFC_BSG_VENDOR_SET_CT_EVENT adding driver private data + * Modify FC_BSG_RPT_CT to operate asynchronously and handle a + timeout condition + * Update code infrastructure to add support for missing SGIO + functionality + * Do not check class specific parameters for FLOGI (CR 97788) + +Changes from 20091221 to 20100112 + + * Changed version number to 8.3.5.3 + * Merge change from upstream scsi-misc-2.6 git tree to move blocking + scsi_eh code from FC LLDs to SCSI FC transport class. + * Clean up ELS commands when unregistering unused ELS commands (CR + 97048) + * Fix an issue in SLI4 when aborted els cmd's xri (SGL) was released + before HBA's abort XRI event (CR 97288) + * Support for Nport ID change after Clear Virtual Link (CR 97188) + * Fixed unsolicited CT command response on SLI4 + * Add QOS Link Speed info (CR 96665) + +Changes from 20091023 to 20091221 + + * Changed version number to 8.3.5.2 + * Fix Dead FCF not triggering discovery of other FCF (CR 97048 + 97049) + * Fix vport->fc_flag set outside of lock caused I/O failure + during pci-func reset (CR 96975) + * Fix driver tries to process failed read fcf record + * Fixed hbq buff adds to receive queue + * Fixed hbq buff only for sli4 + * Fix multi-frame sequence response frames go to wrong DID (CR + 96915) + * Fixed fc header seq_count checks (CR 97010) + * Fixed adapter reset and offline/online stress test failing with + I/O errors (CR 92904) + * Fix vport fails to register VPI after devloss timeout (CR 96740) + * Blocked all SCSI I/O requests from midlayer until target + rediscovery during EEH (CR 95889) + * Fix PCI device vendor for EmulexSecure HBA + * Fixed in-band remote firmware download (CR 96090) + * Made OneCommand CNA set up and use single FCP EQ only under + INTx interrupt mode (CR 96645) + * Fix vport not logging out when being deleted (CR 96339) + * Add new READ_FCF_RECORD failure code + * Remove temporary OneConnect CNA PCI Device IDs + * Fixed panic when unmapping luns (CR 94833) + * Added handling of ELS request for Reinstate Recovery Qualifier + (RRQ) + * Phase out use of ONLINE registers + * Made ABTS WQE go to the same WQ as the WQE to be aborted (CR + 96110) + * Add new READ_FCF_RECORD failure code + * Fixed Dead FCoE port after creating vports (CR 95449) + * Fix crash driver when fcauthd is started (CR 95584) + * Fix hbq pointer corruption (CR 95313) + * Fixed: panic during pci-hot-plug testing (CR 95246) + * Fix reg_vfi and reg_vpi routines to use little endian wwn + * Change default TC BE3 driver identification string to + include model number + * Migrate LUN queue depth ramp up code to scsi mid-layer + * Fix for lost MSI interrupt (CR 95404) + * Fix vport keep-alive does not contain the correct WWN + * Ported the fix on reporting of max_vpi to uppper layer + * Added PCI read after EQarm doorbell PCI write in INTx mode to + flush PCI pipeline + * Fix driver unable to discover targets after FCF DEAD + +Changes from 8.3.5 to 20091023 + + * Changed version number to 8.3.5.1 + * Fixed: lpfc_unreg_vfi failure after devloss timeout. Fixed RPI + bit leak (CR 94542) + * Fix crash due to list corruption while unloading driver (CR + 94889) + * Fix Zeroed frame on wire after FLOGI (CR 94950) + * Fix Vport does not rediscover after FCF goes away + * Fixed the call from lpfc_new_scsi_buf_s3 to use + lpfc_release_scsi_buf_s3 + * Fix memory leak found in lpfc_sli4_read_rev + * Fixed total_scsi_bufs counting + * Fix CVL received on Port 1 not processed by driver + * Fixed locking issue + * Added PCI ID for LPSe12002-ML1-E EmulexSecure Fibre Channel Adapter + * Add DHCHAP support + * Stop and abort all I/Os on HBA for AER uncorrectable non-fatal + error handling + * Made AER sysfs entry point return "Operation not permitted" to + OneConnect HBAs + * Removed the use of the locally defined FC transport layer related + macros + * SLI4_FIXED: Fixed Check for aborted els command + * Fix bug with missing new line characters in log messages (CR + 94092) + * Fix bug with probe_one routines not putting the Scsi_Host back + upon error (CR 94088) + * Fixed discovery failure during quick link bounce + * Add support for Clear Virtual Link + * Handling unsolicited CT exchange sequence abort (lower level + driver part) + * Fix switch name not used in the FCF record for FCoE HBAs + * SLI4: Enabled SLI4 HBA UE error polling error-condition action + code + * Fix Vports unable to be created on Port2 Tigershark HBA (CR + 90670) + * Implemented persistent port disable functionality + * Rewrite lpfc_sli4_scmd_to_wqidx_distr() to handle counter + rollover cleanly + * Added new state in link_state sysfs attribute for persistent link + down + * Fix for firmware dump failure (CR 90533) + * Use PCI config space register to determine SLI rev of the HBA + * Fixed mailbox timeout during HBA reset + * Modified resume_rpi mailbox data structure according to new spec + * Remove always true conditional in lpfc_sli_read_serdes_param() + * SLI4: Do not issue mailbox command when LPFC_HBA_ERROR with + MBX_POLL mode + * Fix accumulated total length not being filled in on SLI4 + unsolicited IOCBs + * Fixed SLI3 inband remote mamagement (CR 91042) + * Fix FCoE Paramers in region 23 not being read correctly + * Wait for HBA POST completion before checking Online and UE + registers (SLI4) + * Fixed static vport creation on SLI4 HBAs + * Fixed vport create not to send init_vpi before REG_VFI + * Remove cast when using pci_read_config_dword() to access + LPFC_SLIREV_CONF_WORD + * Fix use of first_iocbq pointer before checking for NULL + +Changes from 8.3.4 to 8.3.5 + + * Update driver version to 8.3.5 + * Fixed panic during HBA reset. + * Fixed FCoE event tag passed in resume_rpi. + * Fix out of order ELS commands + * Fix UNREG_VPI failure on extended link pull + * Fixed crash while processing unsolicited FC frames. + * Clear retry count in the delayed ELS handler + * Fixed discovery failure during VLAN and quick link bounce. + * Fix mask size for CT field in WQE + * Fix VPI base not used when unregistering VPI on port 1. + * Fix UNREG_VPI mailbox command to unreg the correct VPI + * Fixed Check for aborted els command + * Fix error when trying to load driver with wrong firmware on FCoE HBA. + * Fix bug with probe_one routines not putting the Scsi_Host back upon + error + * Add support for Clear Virtual Link Async Events + * Add support for unsolicited CT exchange sequence abort + * Add 0x0714 OCeXXXXX PCI ID + * Fix crash when "error" is echoed to board_mode sysfs parameter + * Fix FCoE Parameter parsing in regions 23 + * Fix driver crash when creating vport with large number of targets on + SLI4 + * Fix bug with npiv message being logged when it is not supported by + the adapter + * Fix a potential dereferencing mailbox structure after free bug + * Fix firmware crash after vport create with high target count + * Error out requests to set board_mode to warm restart via sysfs on + SLI4 HBAs + * Fix a memory corruption issue during GID_FT IO prep + * Fix failed to allocate XRI message is not a critical failure + * Update and fix formatting in some log messages + * Removed the use of the locally defined FC transport layer related + macros + * Check the rsplen in lpfc_handle_fcp_err function before using rsplen + * Add AER support. + * Fixed Panic/Hang when using polling mode for fcp commands + * Added support for Read_rev mbox bits indicating FIP mode of HBA + * Optimize performance of slow-path handling of els responses + * Add code to cleanup orphaned unsolicited receive sequences + * Fixed Devloss timeout when multiple initiators are in same zone + +Changes from 8.3.3 to 8.3.4 + * Update driver version to 8.3.4 + * Remove spaces before newlines in several log messages + * Add bsg (SGIOv4) support for ELS/CT support + * NPIV vport fixes + * Fix a pair of FCoE issues + * Various SLI3 fixes + * Consistently Implement persistent port disable + * Various SLI4 fixes + + diff --git a/drivers/scsi/lpfc/GNUmakefile b/drivers/scsi/lpfc/GNUmakefile new file mode 100644 index 000000000..afbd23dcf --- /dev/null +++ b/drivers/scsi/lpfc/GNUmakefile @@ -0,0 +1,95 @@ +#/******************************************************************* +# * This file is part of the Emulex Linux Device Driver for * +# * Fibre Channel Host Bus Adapters. * +# * Copyright (C) 2020 Broadcom. All Rights Reserved. The term * +# * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * +# * Copyright (C) 2004-2009 Emulex. All rights reserved. * +# * EMULEX and SLI are trademarks of Emulex. * +# * www.broadcom.com * +# * * +# * This program is free software; you can redistribute it and/or * +# * modify it under the terms of version 2 of the GNU General * +# * Public License as published by the Free Software Foundation. * +# * This program is distributed in the hope that it will be useful. * +# * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * +# * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * +# * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * +# * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * +# * TO BE LEGALLY INVALID. See the GNU General Public License for * +# * more details, a copy of which can be found in the file COPYING * +# * included with this package. * +# *******************************************************************/ +###################################################################### + +KERNELVERSION ?= $(shell uname -r) +BASEINCLUDE ?= /lib/modules/$(KERNELVERSION)/build +DRIVERDIR ?= $(PWD) +DEBUG_FS = $(shell grep CONFIG_DEBUG_FS=y $(BASEINCLUDE)/.config) + +ifeq ($(DEBUG_FS),CONFIG_DEBUG_FS=y) + EXTRA_CFLAGS += -DCONFIG_SCSI_LPFC_DEBUG_FS + export EXTRA_CFLAGS +endif + +ifneq ($(GCOV),) + EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage + EXTRA_CFLAGS += -O0 + export EXTRA_CFLAGS +endif + +clean-files += Modules.symvers Module.symvers Module.markers modules.order + +export clean-files + +$(info GNUmakefile setting EXTRA_CFLAGS to $(EXTRA_CFLAGS)) +default: + $(MAKE) -C $(BASEINCLUDE) M=$(DRIVERDIR) CONFIG_SCSI_LPFC=m modules + +brcmfcoe: + @cp lpfc_attr.c brcmfcoe_attr.c + @cp lpfc_bsg.c brcmfcoe_bsg.c + @cp lpfc_ct.c brcmfcoe_ct.c + @cp lpfc_debugfs.c brcmfcoe_debugfs.c + @cp lpfc_els.c brcmfcoe_els.c + @cp lpfc_hbadisc.c brcmfcoe_hbadisc.c + @cp lpfc_init.c brcmfcoe_init.c + @cp lpfc_mbox.c brcmfcoe_mbox.c + @cp lpfc_mem.c brcmfcoe_mem.c + @cp lpfc_nportdisc.c brcmfcoe_nportdisc.c + @cp lpfc_scsi.c brcmfcoe_scsi.c + @cp lpfc_sli.c brcmfcoe_sli.c + @cp lpfc_vport.c brcmfcoe_vport.c + @cp lpfc_nvme.c brcmfcoe_nvme.c + @cp lpfc_nvmet.c brcmfcoe_nvmet.c + $(MAKE) -C $(BASEINCLUDE) M=$(DRIVERDIR) CONFIG_SCSI_BRCMFCOE=m BUILD_FLAGS=-DBUILD_BRCMFCOE modules + @rm -f brcmfcoe_attr.c + @rm -f brcmfcoe_bsg.c + @rm -f brcmfcoe_ct.c + @rm -f brcmfcoe_debugfs.c + @rm -f brcmfcoe_els.c + @rm -f brcmfcoe_hbadisc.c + @rm -f brcmfcoe_init.c + @rm -f brcmfcoe_mbox.c + @rm -f brcmfcoe_mem.c + @rm -f brcmfcoe_nportdisc.c + @rm -f brcmfcoe_scsi.c + @rm -f brcmfcoe_sli.c + @rm -f brcmfcoe_vport.c + @rm -f brcmfcoe_nvme.c + @rm -f brcmfcoe_nvmet.c + + +install: + @rm -f /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/lpfc.ko + install -d /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/lpfc + install -c lpfc.ko /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/lpfc + depmod -a + +brcmfcoeinstall: + @rm -f /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/brcmfcoe.ko + install -d /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/brcmfcoe + install -c brcmfcoe.ko /lib/modules/$(KERNELVERSION)/kernel/drivers/scsi/brcmfcoe + depmod -a + +clean: + $(MAKE) -C $(BASEINCLUDE) M=$(DRIVERDIR) CONFIG_SCSI_LPFC=m clean diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 092a971d0..54e30da2b 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -1,8 +1,8 @@ #/******************************************************************* # * This file is part of the Emulex Linux Device Driver for * # * Fibre Channel Host Bus Adapters. * -# * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * -# * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * +# * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * +# * Broadcom refers to Broadcom Inc. and/or its subsidiaries. * # * Copyright (C) 2004-2012 Emulex. All rights reserved. * # * EMULEX and SLI are trademarks of Emulex. * # * www.broadcom.com * @@ -21,16 +21,116 @@ # *******************************************************************/ ###################################################################### -ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage -ccflags-$(GCOV) += -O0 +SUBLEVEL = $(shell echo ${KERNELVERSION} | \ +sed -e 's/[0-9]*.[0-9]*.\([0-9]*\).[0-9]*.*/\1/') +EXTRAVERSION = $(shell echo ${KERNELRELEASE} | \ +sed -e 's/[0-9]*.[0-9]*.[0-9]*.\([0-9]*\).*/\1/') +MAJORVERSION = $(shell echo ${KERNELVERSION} | \ +sed -e 's/\([0-9]*\).*/\1/') +MINORVERSION = $(shell echo ${KERNELVERSION} | \ +sed -e 's/[0-9]*.\([0-9]*\).*/\1/') -ifdef WARNINGS_BECOME_ERRORS -ccflags-y += -Werror +EXTRA_CFLAGS += -Werror -DKERNEL_MAJOR=${MAJORVERSION} -DKERNEL_MINOR=${MINORVERSION} + +ifneq ($(GCOV),) + EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage + EXTRA_CFLAGS += -O0 endif +# +# DISTRO KERNELVERSION SUBLEVEL EXTRAVERSION +# sles15-sp3 5.3.18-37 18 37 +# sles15-sp2 5.3.18-22 18 22 +# sles15-sp1 4.12.14-195 14 195 +# sles15-sp0 4.12.14-23 14 23 +# sles12-sp5 4.12.14-100 14 100 +# sles12-sp4 4.12.14-94.4 14 94 +# rhel8.4 4.18.0-259.el8 Alpha-1.0 +# rhel8.3 4.18.0-240.el8 +# rhel8.2 4.18.0-193.el8 +# rhel8.1 4.18.0-147.el8 +# rhel8.0 4.18.0-80.el8 +# + +ifeq (,$(findstring -DBUILD_BRCMFCOE,$(BUILD_FLAGS))) +ifeq ("$(wildcard /etc/debian_version)","") + EXTRA_CFLAGS += -DBUILD_NVME +endif +endif + +# This will pick out a Citrix kernel, xs5.6 / xs6.0 / xs6.1 +EXTRAXSINFO = $(shell echo ${KERNELVERSION} | \ +grep 'xs[156].[016]' | sed -e 's/.*xs.*/xs/') + +ifeq ($(EXTRAXSINFO),xs) + EXTRA_CFLAGS += -DBUILD_CITRIX_XS +endif +EXTRAXSINFO = $(shell echo ${KERNELVERSION} | \ +grep 'el8' | sed -e 's/.*el8.*/el8/') + +ifeq ($(EXTRAXSINFO),el8) + EXTRA_CFLAGS += -DBUILD_RHEL8 + RHEL8_NZ = $(shell echo "${KERNELVERSION} 4.18.0-83.el8.x86_64" | \ + tr " " "\n" | sort -V | head -n1) +ifeq ($(RHEL8_NZ), 4.18.0-83.el8.x86_64) + EXTRA_CFLAGS += -DBUILD_RHEL8_NZ +endif +ifeq ($(shell test $(EXTRAVERSION) -ge 211; echo $$?), 0) + EXTRA_CFLAGS += -DBUILD_RHEL83 +endif +# RHEL 8.4 adds NVME1+ Addendum +ifeq ($(shell test $(EXTRAVERSION) -ge 259; echo $$?), 0) + EXTRA_CFLAGS += -DBUILD_NVME_PLUS +endif +endif + +ifneq ("$(wildcard /etc/os-release)","") + SLES15SP = $(shell grep -q 'sles:15:sp' /etc/os-release && echo 1) +ifeq ($(SLES15SP),1) + EXTRA_CFLAGS += -DBUILD_SLES15SP +endif + SLES12SP5 = $(shell grep -q 'sles:12:sp5' /etc/os-release && echo 1) +ifeq ($(SLES12SP5),1) + EXTRA_CFLAGS += -DBUILD_SLES12SP5 +endif + SLES15SP2 = $(shell grep -q 'sles:15:sp2' /etc/os-release && echo 1) +ifeq ($(SLES15SP2),1) + EXTRA_CFLAGS += -DBUILD_SLES15SP2 -DBUILD_NVME_PLUS +endif + SLES15SP3 = $(shell grep -q 'sles:15:sp3' /etc/os-release && echo 1) +ifeq ($(SLES15SP3),1) + EXTRA_CFLAGS += -DBUILD_SLES15SP2 -DBUILD_NVME_PLUS +endif +endif + +# This will pick out an openEuler kernel +EXTRAOE1INFO = $(shell echo ${KERNELVERSION} | grep oe1 | \ + sed -e 's/.*oe1.*/oe1/') +ifeq ($(EXTRAOE1INFO),oe1) +ifneq ("$(wildcard /etc/os-release)","") +OE1_20 = $(shell grep -q 'VERSION="20.' /etc/os-release && echo 1) +ifeq ($(OE1_20),1) + EXTRA_CFLAGS += -DBUILD_OE1_20 +endif +endif +endif + +# This will pick out a xen kernel +EXTRAXENINFO = $(shell echo ${KERNELVERSION} | \ +grep 'xen' | sed -e 's/.*xen.*/xen/') + +EXTRA_CFLAGS += ${BUILD_FLAGS} + obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o \ lpfc_hbadisc.o lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o \ lpfc_scsi.o lpfc_attr.o lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o \ - lpfc_nvme.o lpfc_nvmet.o + lpfc_nvme.o lpfc_nvmet.o lpfc_auth.o + +obj-$(CONFIG_SCSI_BRCMFCOE) := brcmfcoe.o + +brcmfcoe-objs := brcmfcoe_mem.o brcmfcoe_sli.o brcmfcoe_ct.o brcmfcoe_els.o brcmfcoe_hbadisc.o \ + brcmfcoe_init.o brcmfcoe_mbox.o brcmfcoe_nportdisc.o brcmfcoe_scsi.o brcmfcoe_attr.o \ + brcmfcoe_vport.o brcmfcoe_debugfs.o brcmfcoe_bsg.o \ + brcmfcoe_nvme.o brcmfcoe_nvmet.o diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8943d42fc..3cf85cc29 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -22,6 +22,7 @@ *******************************************************************/ #include +#include #include #include @@ -29,6 +30,15 @@ #define CONFIG_SCSI_LPFC_DEBUG_FS #endif +/* define XS6.5 and XS7.0 kernel version since + * XenServer build environment does not pass + * these values in + */ +#if defined(XS_API) +#define KERNEL_MAJOR 3 +#define KERNEL_MINOR 10 +#endif + struct lpfc_sli2_slim; #define ELX_MODEL_NAME_SIZE 80 @@ -55,6 +65,7 @@ struct lpfc_sli2_slim; #define LPFC_MAX_SG_TABLESIZE 0xffff #define LPFC_MIN_SG_SLI4_BUF_SZ 0x800 /* based on LPFC_DEFAULT_SG_SEG_CNT */ #define LPFC_MAX_BG_SLI4_SEG_CNT_DIF 128 /* sg element count for BlockGuard */ +#define LPFC_MAX_ED_SLI4_SEG_CNT_DIF 256 /* sg element count for ExternalDIF */ #define LPFC_MAX_SG_SEG_CNT_DIF 512 /* sg element count per scsi cmnd */ #define LPFC_MAX_SG_SEG_CNT 4096 /* sg element count per scsi cmnd */ #define LPFC_MIN_SG_SEG_CNT 32 /* sg element count per scsi cmnd */ @@ -69,6 +80,9 @@ struct lpfc_sli2_slim; #define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */ #define LPFC_MIN_TGT_QDEPTH 10 #define LPFC_MAX_TGT_QDEPTH 0xFFFF +#define LPFC_MIN_LUN_QDEPTH 1 +#define LPFC_DEF_LUN_QDEPTH 64 +#define LPFC_MAX_LUN_QDEPTH 512 #define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data collection. */ @@ -114,6 +128,12 @@ struct lpfc_sli2_slim; #define LPFC_MBX_NO_WAIT 0 #define LPFC_MBX_WAIT 1 +#define LPFC_CFG_PARAM_MAGIC_NUM 0xFEAA0005 +#define LPFC_PORT_CFG_NAME "/cfg/port.cfg" + +#define lpfc_rangecheck(val, min, max) \ + ((uint)(val) >= (uint)(min) && (val) <= (max)) + enum lpfc_polling_flags { ENABLE_FCP_RING_POLLING = 0x1, DISABLE_FCP_RING_INT = 0x2 @@ -207,8 +227,7 @@ typedef struct lpfc_vpd { } rev; struct { #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 :19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 :20; /* Reserved */ uint32_t rsvd2 : 3; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ @@ -230,8 +249,7 @@ typedef struct lpfc_vpd { uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t rsvd2 : 3; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 :19; /* Reserved */ + uint32_t rsvd3 :20; /* Reserved */ #endif } sli3Feat; } lpfc_vpd_t; @@ -262,13 +280,15 @@ struct lpfc_stats { uint32_t elsRcvPRLI; uint32_t elsRcvLIRR; uint32_t elsRcvRLS; - uint32_t elsRcvRPS; uint32_t elsRcvRPL; uint32_t elsRcvRRQ; uint32_t elsRcvRTV; uint32_t elsRcvECHO; uint32_t elsRcvLCB; uint32_t elsRcvRDP; + uint32_t elsRcvAUTH; + uint32_t elsRcvFPIN; + uint32_t elsRcvEDC; uint32_t elsXmitFLOGI; uint32_t elsXmitFDISC; uint32_t elsXmitPLOGI; @@ -282,6 +302,8 @@ struct lpfc_stats { uint32_t elsXmitFARPR; uint32_t elsXmitACC; uint32_t elsXmitLSRJT; + uint32_t elsXmitRDF; + uint32_t elsXmitEDC; uint32_t frameRcvBcast; uint32_t frameRcvMulti; @@ -335,6 +357,52 @@ enum hba_state { LPFC_HBA_ERROR = -1 }; +/* Structure used to identify all devices controlled + * by the External DIF logic. + */ +struct lpfc_external_dif_support { + struct list_head listentry; + struct lpfc_name portName; + uint64_t lun; + uint16_t sid; + uint8_t dif_info; + uint8_t state; +#define LPFC_EDSM_IGNORE 0 +#define LPFC_EDSM_INIT 1 +#define LPFC_EDSM_NEEDS_INQUIRY 2 +#define LPFC_EDSM_PATH_STANDBY 3 +#define LPFC_EDSM_PATH_READY 4 +#define LPFC_EDSM_PATH_CHECK 5 + uint16_t inq_retry; +#define LPFC_EDSM_MAX_RETRY 3 + uint16_t inq_cnt; + uint32_t err3f_cnt; + uint32_t err4b_cnt; +}; + +/* Struct used to identify External DIF vendor specific info */ +struct lpfc_vendor_dif { + uint8_t length; + uint8_t version; + uint8_t dif_info; +#define LPFC_FDIF_ATO 0x01 +#define LPFC_FDIF_REFCHK 0x02 +#define LPFC_FDIF_APPCHK 0x04 +#define LPFC_FDIF_GRDCHK 0x08 +#define LPFC_FDIF_SPTMASK 0x70 +#define LPFC_FDIF_PROTECT 0x80 + uint8_t reserved1; +}; + +/* Defines used to identify a External DIF device */ +#define LPFC_INQ_VID_OFFSET 8 +#define LPFC_INQ_VDIF_OFFSET 168 +#define LPFC_INQ_FDIF_SZ (LPFC_INQ_VDIF_OFFSET + 4) +#define LPFC_INQ_FDIF_VENDOR "3PARdata" /* Vendor Identification */ +#define LPFC_INQ_FDIF_VERSION 1 +#define LPFC_INQ_FDIF_SIZE 2 +#define LPFC_FDIF_CDB_PROTECT 0x20 /* Set RD/WR PROTECT = 001 */ + struct lpfc_trunk_link_state { enum hba_state state; uint8_t fault; @@ -347,6 +415,168 @@ struct lpfc_trunk_link { link3; }; +/* Format of congestion module parameters */ +struct lpfc_cgn_param { + uint32_t cgn_param_magic; + uint8_t cgn_param_version; /* version 1 */ + uint8_t cgn_param_mode; /* 0=off 1=managed 2=monitor only */ +#define LPFC_CFG_OFF 0 +#define LPFC_CFG_MANAGED 1 +#define LPFC_CFG_MONITOR 2 + uint8_t cgn_rsvd1; /* Unused for CMF */ + uint8_t cgn_rsvd2; /* Unused for CMF */ + uint8_t cgn_param_acr; /* 0=conserve 1=moderate 2=severe */ +#define LPFC_CFG_CONSERVE 0 +#define LPFC_CFG_MODERATE 1 +#define LPFC_CFG_SEVERE 2 + uint8_t cgn_param_rxburst; /* Burst in 512K units */ +#define LPFC_CFG_BURST_MIN 0 +#define LPFC_CFG_BURST_MAX 32 +#define LPFC_CFG_BURST_DEF 4 + uint8_t cgn_param_rxbw; /* BW in units of 5% */ +#define LPFC_CFG_BW_MIN 1 +#define LPFC_CFG_BW_MAX 20 +#define LPFC_CFG_BW_DEF 18 + uint8_t cgn_param_acr_min_rxbw; /* in units of 5%, must be < acrrxbw */ +#define LPFC_CFG_DEFAULT_MIN_BW 8 + uint8_t cgn_param_acr_scale; /* used in recovery and ramp up/down */ +#define LPFC_CFG_LOW_SCALE 1 +#define LPFC_CFG_DEFAULT_SCALE 10 /* 100% */ +#define LPFC_CFG_HIGH_SCALE 255 + uint8_t cgn_param_acr_max_rxburst; /* Burst in 512K units */ + uint8_t cgn_param_acr_max_rxbw; /* BW in units of 5% */ + uint8_t cgn_param_acr_min_rxburst; /* units of 5%, be < acrrxburst */ +}; + +/* Max number of days of congestion data */ +#define LPFC_MAX_CGN_DAYS 10 + +/* Format of congestion buffer info + * This structure defines memory thats allocated and registered with + * the HBA firmware. When adding or removing fields from this structure + * the alignment must match the HBA firmware. + */ + +struct lpfc_cgn_info { + /* Header */ + __le16 cgn_info_size; /* is sizeof(struct lpfc_cgn_info) */ + uint8_t cgn_info_version; /* represents format of structure */ +#define LPFC_CGN_INFO_V1 1 +#define LPFC_CGN_INFO_V2 2 +#define LPFC_CGN_INFO_V3 3 + uint8_t cgn_info_mode; /* 0=off 1=managed 2=monitor only */ + uint8_t cgn_info_detect; /* 1=driver 2-fabric 3=both */ + uint8_t cgn_info_action; /* 0=fixed 1=adaptive */ + uint8_t cgn_info_acr; /* 0=conserve 1=moderate 2=aggressive */ + uint8_t cgn_info_rxburst; /* Burst in 512K units */ + uint8_t cgn_info_rxbw; /* BW in units of 5% */ + + /* Start Time */ + uint8_t cgn_info_month; + uint8_t cgn_info_day; + uint8_t cgn_info_year; + uint8_t cgn_info_hour; + uint8_t cgn_info_minute; + uint8_t cgn_info_second; + + /* minute / hours / daily indices */ + uint8_t cgn_index_minute; + uint8_t cgn_index_hour; + uint8_t cgn_index_day; + + __le16 cgn_warn_freq; + __le16 cgn_alarm_freq; + __le16 cgn_lunq; + uint8_t cgn_pad1[8]; + + /* Driver Information */ + __le16 cgn_drvr_min[60]; + __le32 cgn_drvr_hr[24]; + __le32 cgn_drvr_day[LPFC_MAX_CGN_DAYS]; + + /* Congestion Warnings */ + __le16 cgn_warn_min[60]; + __le32 cgn_warn_hr[24]; + __le32 cgn_warn_day[LPFC_MAX_CGN_DAYS]; + + /* Latency Information */ + __le32 cgn_latency_min[60]; + __le32 cgn_latency_hr[24]; + __le32 cgn_latency_day[LPFC_MAX_CGN_DAYS]; + + /* Bandwidth Information */ + __le16 cgn_bw_min[60]; + __le16 cgn_bw_hr[24]; + __le16 cgn_bw_day[LPFC_MAX_CGN_DAYS]; + + /* Congestion Alarms */ + __le16 cgn_alarm_min[60]; + __le32 cgn_alarm_hr[24]; + __le32 cgn_alarm_day[LPFC_MAX_CGN_DAYS]; + + /* Start of congestion statistics */ + uint8_t cgn_stat_npm; /* Notifications per minute */ + + /* Start Time */ + uint8_t cgn_stat_month; + uint8_t cgn_stat_day; + uint8_t cgn_stat_year; + uint8_t cgn_stat_hour; + uint8_t cgn_stat_minute; + uint8_t cgn_pad2[2]; + + __le32 cgn_notification; + __le32 cgn_peer_notification; + __le32 link_integ_notification; + __le32 delivery_notification; + + uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */ + uint8_t cgn_stat_cgn_day; + uint8_t cgn_stat_cgn_year; + uint8_t cgn_stat_cgn_hour; + uint8_t cgn_stat_cgn_min; + uint8_t cgn_stat_cgn_sec; + + uint8_t cgn_stat_peer_month; /* Last peer congestion FPIN */ + uint8_t cgn_stat_peer_day; + uint8_t cgn_stat_peer_year; + uint8_t cgn_stat_peer_hour; + uint8_t cgn_stat_peer_min; + uint8_t cgn_stat_peer_sec; + + uint8_t cgn_stat_lnk_month; /* Last link integrity FPIN */ + uint8_t cgn_stat_lnk_day; + uint8_t cgn_stat_lnk_year; + uint8_t cgn_stat_lnk_hour; + uint8_t cgn_stat_lnk_min; + uint8_t cgn_stat_lnk_sec; + + uint8_t cgn_stat_del_month; /* Last delivery notification FPIN */ + uint8_t cgn_stat_del_day; + uint8_t cgn_stat_del_year; + uint8_t cgn_stat_del_hour; + uint8_t cgn_stat_del_min; + uint8_t cgn_stat_del_sec; +#define LPFC_CGN_STAT_SIZE 48 +#define LPFC_CGN_DATA_SIZE (sizeof(struct lpfc_cgn_info) - \ + LPFC_CGN_STAT_SIZE - sizeof(uint32_t)) + + __le32 cgn_info_crc; +#define LPFC_CGN_CRC32_MAGIC_NUMBER 0x1EDC6F41 +#define LPFC_CGN_CRC32_SEED 0xFFFFFFFF +}; + +#define LPFC_CGN_INFO_SZ (sizeof(struct lpfc_cgn_info) - \ + sizeof(uint32_t)) + +struct lpfc_cgn_stat { + atomic64_t total_bytes; + atomic64_t rcv_bytes; + atomic64_t rx_latency; +#define LPFC_CGN_NOT_SENT 0xFFFFFFFFFFFFFFFFLL + atomic_t rx_io_cnt; +}; + struct lpfc_vport { struct lpfc_hba *phba; struct list_head listentry; @@ -388,6 +618,7 @@ struct lpfc_vport { #define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ #define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ #define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */ +#define FC_CT_CGN_RPA 0x4000000 /* CGN RPA sent to switch */ uint32_t ct_flags; #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ @@ -397,6 +628,7 @@ struct lpfc_vport { #define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ struct list_head fc_nodes; + uint32_t throttle_cnt; /* Keep counters for the number of entries in each list. */ uint16_t fc_plogi_cnt; @@ -479,10 +711,11 @@ struct lpfc_vport { #ifdef CONFIG_SCSI_LPFC_DEBUG_FS struct dentry *debug_disc_trc; struct dentry *debug_nodelist; + struct dentry *debug_ediflist; struct dentry *debug_nvmestat; struct dentry *debug_scsistat; - struct dentry *debug_nvmektime; - struct dentry *debug_cpucheck; + struct dentry *debug_ioktime; + struct dentry *debug_hdwqstat; struct dentry *vport_debugfs_root; struct lpfc_debugfs_trc *disc_trc; atomic_t disc_trc_cnt; @@ -496,6 +729,11 @@ struct lpfc_vport { #define FAWWPN_SET 2 #define FAWWPN_PARAM_CHG 4 + struct throttle_history log; /* Throttle log history for phba */ + /* Used to discover External DIF devices */ + struct list_head external_dif_list; + spinlock_t external_dif_lock; /* lock for external_dif_list */ + uint16_t fdmi_num_disc; uint32_t fdmi_hba_mask; uint32_t fdmi_port_mask; @@ -605,6 +843,12 @@ struct lpfc_epd_pool { spinlock_t lock; /* lock for expedite pool */ }; +enum ras_state { + INACTIVE, + REG_INPROGRESS, + ACTIVE +}; + struct lpfc_ras_fwlog { uint8_t *fwlog_buff; uint32_t fw_buffcount; /* Buffer size posted to FW */ @@ -621,7 +865,28 @@ struct lpfc_ras_fwlog { bool ras_enabled; /* Ras Enabled for the function */ #define LPFC_RAS_DISABLE_LOGGING 0x00 #define LPFC_RAS_ENABLE_LOGGING 0x01 - bool ras_active; /* RAS logging running state */ + enum ras_state state; /* RAS logging running state */ +}; + +#define DBG_LOG_STR_SZ 256 +#define DBG_LOG_SZ 256 + +struct dbg_log_ent { + char log[DBG_LOG_STR_SZ]; + u64 t_ns; +}; + +enum lpfc_irq_chann_mode { + /* Assign IRQs to all possible cpus that have hardware queues */ + NORMAL_MODE, + + /* Assign IRQs only to cpus on the same numa node as HBA */ + NUMA_MODE, + + /* Assign IRQs only on non-hyperthreaded CPUs. This is the + * same as normal_mode, but assign IRQS only on physical CPUs. + */ + NHT_MODE, }; struct lpfc_hba { @@ -637,7 +902,7 @@ struct lpfc_hba { (struct lpfc_hba *, struct lpfc_io_buf *); void (*lpfc_rampdown_queue_depth) (struct lpfc_hba *); - void (*lpfc_scsi_prep_cmnd) + int (*lpfc_scsi_prep_cmnd) (struct lpfc_vport *, struct lpfc_io_buf *, struct lpfc_nodelist *); @@ -674,9 +939,9 @@ struct lpfc_hba { void (*lpfc_stop_port) (struct lpfc_hba *); int (*lpfc_hba_init_link) - (struct lpfc_hba *, uint32_t); + (struct lpfc_hba *); int (*lpfc_hba_down_link) - (struct lpfc_hba *, uint32_t); + (struct lpfc_hba *); int (*lpfc_selective_reset) (struct lpfc_hba *); @@ -693,6 +958,9 @@ struct lpfc_hba { struct workqueue_struct *wq; struct delayed_work eq_delay_work; +#define LPFC_IDLE_STAT_DELAY 1000 + struct delayed_work idle_stat_delay_work; + struct lpfc_sli sli; uint8_t pci_dev_grp; /* lpfc PCI dev group: 0x0, 0x1, 0x2,... */ uint32_t sli_rev; /* SLI2, SLI3, or SLI4 */ @@ -725,7 +993,8 @@ struct lpfc_hba { #define HBA_FCOE_MODE 0x4 /* HBA function in FCoE Mode */ #define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ -#define ELS_XRI_ABORT_EVENT 0x40 +#define HBA_PERSISTENT_TOPO 0x20 /* Persistent topology support in hba */ +#define ELS_XRI_ABORT_EVENT 0x40 /* ELS_XRI abort event was queued */ #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ #define FCF_TS_INPROG 0x200 /* FCF table scan in progress */ @@ -742,7 +1011,12 @@ struct lpfc_hba { * capability */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ +#define HBA_CGN_BOTTOM 0x200000 /* HBA Congestion mgmt hits bottom */ +#define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */ #define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */ +#define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */ +#define HBA_HBEAT_INP 0x2000000 /* mbox HBEAT is in progress */ +#define HBA_HBEAT_TMO 0x4000000 /* HBEAT initiated after timeout */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; @@ -805,6 +1079,9 @@ struct lpfc_hba { uint32_t cfg_xpsgl; uint32_t cfg_enable_npiv; uint32_t cfg_enable_rrq; +#ifndef NO_APEX + uint32_t cfg_enable_fcp_priority; +#endif uint32_t cfg_topology; uint32_t cfg_link_speed; #define LPFC_FCF_FOV 1 /* Fast fcf failover */ @@ -824,9 +1101,9 @@ struct lpfc_hba { uint32_t cfg_use_msi; uint32_t cfg_auto_imax; uint32_t cfg_fcp_imax; - uint32_t cfg_force_rscn; uint32_t cfg_cq_poll_threshold; uint32_t cfg_cq_max_proc_limit; + uint32_t cfg_force_rscn; uint32_t cfg_fcp_cpu_map; uint32_t cfg_fcp_mq_threshold; uint32_t cfg_hdw_queue; @@ -844,8 +1121,6 @@ struct lpfc_hba { uint32_t cfg_nvme_seg_cnt; uint32_t cfg_scsi_seg_cnt; uint32_t cfg_sg_dma_buf_size; - uint64_t cfg_soft_wwnn; - uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; @@ -867,24 +1142,27 @@ struct lpfc_hba { uint32_t cfg_enable_bg; uint32_t cfg_prot_mask; uint32_t cfg_prot_guard; + uint32_t cfg_external_dif; uint32_t cfg_hostmem_hgp; uint32_t cfg_log_verbose; uint32_t cfg_enable_fc4_type; uint32_t cfg_aer_support; uint32_t cfg_sriov_nr_virtfn; uint32_t cfg_request_firmware_upgrade; - uint32_t cfg_iocb_cnt; uint32_t cfg_suppress_link_up; + uint32_t cfg_throttle_log_cnt; + uint32_t cfg_throttle_log_time; + struct throttle_history log; /* Throttle log history for phba */ uint32_t cfg_rrq_xri_bitmap_sz; uint32_t cfg_delay_discovery; uint32_t cfg_sli_mode; #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ #define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */ - uint32_t cfg_enable_dss; uint32_t cfg_fdmi_on; #define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */ #define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */ + uint32_t cfg_enable_e2e; uint32_t cfg_enable_SmartSAN; uint32_t cfg_enable_mds_diags; uint32_t cfg_ras_fwlog_level; @@ -896,7 +1174,13 @@ struct lpfc_hba { #define LPFC_ENABLE_NVME 2 #define LPFC_ENABLE_BOTH 3 uint32_t cfg_enable_pbde; + uint32_t cfg_enable_scsi_mq; + uint32_t cfg_enable_auth; +#define LPFC_AUTH_DISABLE 0 +#define LPFC_AUTH_ENABLE 1 +#if defined(BUILD_NVME) struct nvmet_fc_target_port *targetport; +#endif lpfc_vpd_t vpd; /* vital product data */ struct pci_dev *pcidev; @@ -906,6 +1190,15 @@ struct lpfc_hba { uint32_t work_hs; /* HS stored in case of ERRAT */ uint32_t work_status[2]; /* Extra status from SLIM */ + uint32_t nvme_pendq_cnt; + struct list_head nvme_pendq; + spinlock_t nvme_pendq_lock; + struct list_head nvme_abts_pendq; + atomic_t nvme_abts_cnt; + + struct workqueue_struct *nvme_io; + struct work_struct nvme_defer_work; + wait_queue_head_t work_waitq; struct task_struct *worker_thread; unsigned long data_flags; @@ -963,8 +1256,6 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ - uint8_t soft_wwn_enable; - struct timer_list fcp_poll_timer; struct timer_list eratt_poll; uint32_t eratt_poll_interval; @@ -983,6 +1274,7 @@ struct lpfc_hba { uint32_t total_iocbq_bufs; struct list_head active_rrq_list; spinlock_t hbalock; + struct work_struct unblock_request_work; /* SCSI layer unblock IOs */ /* dma_mem_pools */ struct dma_pool *lpfc_sg_dma_buf_pool; @@ -991,7 +1283,6 @@ struct lpfc_hba { struct dma_pool *lpfc_drb_pool; /* data receive buffer pool */ struct dma_pool *lpfc_nvmet_drb_pool; /* data receive buffer pool */ struct dma_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */ - struct dma_pool *txrdy_payload_pool; struct dma_pool *lpfc_cmd_rsp_buf_pool; struct lpfc_dma_pool lpfc_mbuf_safety_pool; @@ -1001,9 +1292,11 @@ struct lpfc_hba { mempool_t *active_rrq_pool; struct fc_host_statistics link_stats; + enum lpfc_irq_chann_mode irq_chann_mode; enum intr_type_t intr_type; uint32_t intr_mode; #define LPFC_INTR_ERROR 0xFFFFFFFF + struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; struct list_head port_list; spinlock_t port_list_lock; /* lock for port_list mutations */ struct lpfc_vport *pport; /* physical lpfc_vport pointer */ @@ -1023,6 +1316,8 @@ struct lpfc_hba { uint16_t vpi_count; struct list_head lpfc_vpi_blk_list; + struct list_head lpfc_auth_active_cfg_list; + /* Data structure used by fabric iocb scheduler */ struct list_head fabric_iocb_list; atomic_t fabric_iocb_count; @@ -1056,6 +1351,9 @@ struct lpfc_hba { #ifdef LPFC_HDWQ_LOCK_STAT struct dentry *debug_lockstat; #endif + struct dentry *debug_cgn_buffer; + struct dentry *debug_rx_monitor; + struct dentry *debug_ras_log; atomic_t nvmeio_trc_cnt; uint32_t nvmeio_trc_size; uint32_t nvmeio_trc_output_idx; @@ -1099,7 +1397,6 @@ struct lpfc_hba { unsigned long last_completion_time; unsigned long skipped_hb; struct timer_list hb_tmofunc; - uint8_t hb_outstanding; struct timer_list rrq_tmr; enum hba_temp_state over_temp_state; /* ndlp reference management */ @@ -1150,8 +1447,10 @@ struct lpfc_hba { uint32_t iocb_cnt; uint32_t iocb_max; atomic_t sdev_cnt; - uint8_t fips_spec_rev; - uint8_t fips_level; + uint8_t dif_wqidx; +#ifndef NO_APEX + struct lpfc_fcp_pri_rules *fcp_priority_rules; +#endif spinlock_t devicelock; /* lock for luns list */ mempool_t *device_data_mem_pool; struct list_head luns; @@ -1169,12 +1468,11 @@ struct lpfc_hba { uint16_t sfp_warning; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint16_t cpucheck_on; + uint16_t hdwqstat_on; #define LPFC_CHECK_OFF 0 #define LPFC_CHECK_NVME_IO 1 -#define LPFC_CHECK_NVMET_RCV 2 -#define LPFC_CHECK_NVMET_IO 4 -#define LPFC_CHECK_SCSI_IO 8 +#define LPFC_CHECK_NVMET_IO 2 +#define LPFC_CHECK_SCSI_IO 4 uint16_t ktime_on; uint64_t ktime_data_samples; uint64_t ktime_status_samples; @@ -1210,6 +1508,72 @@ struct lpfc_hba { uint64_t ktime_seg10_min; uint64_t ktime_seg10_max; #endif + /* CMF objects */ + struct lpfc_cgn_stat __percpu *cmf_stat; + uint32_t cmf_interval_rate; /* timer interval limit in ms */ + uint32_t cmf_timer_cnt; +#define LPFC_CMF_INTERVAL 90 + uint64_t cmf_link_byte_count; + uint64_t cmf_max_line_rate; + uint64_t cmf_max_bytes_per_interval; + uint64_t cmf_last_sync_bw; +#define LPFC_CMF_BLK_SIZE 512 + struct hrtimer cmf_timer; + atomic_t cmf_bw_wait; + atomic_t cmf_busy; + atomic_t cmf_stop_io; /* To block request and stop IO's */ + uint32_t cmf_active_mode; + uint32_t cmf_info_per_interval; +#define LPFC_MAX_CMF_INFO 32 + struct timespec64 cmf_latency; /* Interval congestion timestamp */ + uint32_t cmf_last_ts; /* Interval congestion time (ms) */ + uint32_t cmf_active_info; + + /* Signal / FPIN handling for Congestion Mgmt */ + u8 cgn_reg_fpin; /* Negotiated value from RDF */ + u8 cgn_init_reg_fpin; /* Initial value from READ_CONFIG */ +#define LPFC_CGN_FPIN_NONE 0x0 +#define LPFC_CGN_FPIN_WARN 0x1 +#define LPFC_CGN_FPIN_ALARM 0x2 +#define LPFC_CGN_FPIN_BOTH (LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM) + u8 cgn_reg_signal; /* Negotiated value from EDC */ + u8 cgn_init_reg_signal; /* Initial value from READ_CONFIG */ +#define LPFC_CGN_SIGNAL_NO_SPT 0x0 +#define LPFC_CGN_SIGNAL_WARN 0x1 +#define LPFC_CGN_SIGNAL_BOTH 0x2 + u16 cgn_fpin_frequency; +#define LPFC_FPIN_INIT_FREQ 0xffff + u32 cgn_sig_freq; + u32 cgn_acqe_cnt; + + /* RX monitor handling for CMF */ + struct rxtable_entry *rxtable; /* RX_monitor information */ + atomic_t rxtable_idx_head; +#define LPFC_RXMONITOR_TABLE_IN_USE (LPFC_MAX_RXMONITOR_ENTRY + 73) + atomic_t rxtable_idx_tail; + atomic_t rx_max_read_cnt; /* Maximum read bytes */ + uint64_t rx_block_cnt; + + /* Congestion parameters from flash */ + struct lpfc_cgn_param cgn_p; + + /* Congestion buffer information */ + struct lpfc_dmabuf *cgn_i; /* Congestion Info buffer */ + atomic_t cgn_fabric_warn_cnt; /* Total warning cgn events for info */ + atomic_t cgn_fabric_alarm_cnt; /* Total alarm cgn events for info */ + atomic_t cgn_sync_warn_cnt; /* Total warning events for SYNC wqe */ + atomic_t cgn_sync_alarm_cnt; /* Total alarm events for SYNC wqe */ + atomic_t cgn_driver_evt_cnt; /* Total driver cgn events for fmw */ + atomic_t cgn_latency_evt_cnt; + struct timespec64 cgn_daily_ts; + atomic64_t cgn_latency_evt; /* Avg latency per minute */ + unsigned long cgn_evt_timestamp; +#define LPFC_CGN_TIMER_TO_MIN 60000 /* ms in a minute */ + uint32_t cgn_evt_minute; +#define LPFC_SEC_MIN 60 +#define LPFC_MIN_HOUR 60 +#define LPFC_HOUR_DAY 24 +#define LPFC_MIN_DAY (LPFC_MIN_HOUR * LPFC_HOUR_DAY) struct hlist_node cpuhp; /* used for cpuhp per hba callback */ struct timer_list cpuhp_poll_timer; @@ -1219,6 +1583,31 @@ struct lpfc_hba { #define LPFC_POLL_SLOWPATH 1 /* called from slowpath */ char os_host_name[MAXHOSTNAMELEN]; + + /* SCSI host template information - for physical port */ + struct scsi_host_template port_template; + /* SCSI host template information - for all vports */ + struct scsi_host_template vport_template; + atomic_t dbg_log_idx; + atomic_t dbg_log_cnt; + atomic_t dbg_log_dmping; + struct dbg_log_ent dbg_log[DBG_LOG_SZ]; +}; + +#define LPFC_MAX_RXMONITOR_ENTRY 800 +#define LPFC_MAX_RXMONITOR_DUMP 32 +struct rxtable_entry { + uint64_t total_bytes; /* Total no of read bytes requested */ + uint64_t rcv_bytes; /* Total no of read bytes completed */ + uint64_t avg_io_size; + uint64_t avg_io_latency;/* Average io latency in microseconds */ + uint64_t max_read_cnt; /* Maximum read bytes */ + uint64_t max_bytes_per_interval; + uint32_t cmf_busy; + uint32_t cmf_info; /* CMF_SYNC_WQE info */ + uint32_t io_cnt; + uint32_t timer_utilization; + uint32_t timer_interval; }; static inline struct Scsi_Host * @@ -1327,3 +1716,24 @@ lpfc_sli4_mod_hba_eq_delay(struct lpfc_hba *phba, struct lpfc_queue *eq, writel(reg_data.word0, phba->sli4_hba.u.if_type2.EQDregaddr); eq->q_mode = delay; } + +/** + * lpfc_next_online_cpu - Finds next online CPU on cpumask + * @mask: Pointer to phba's cpumask member. + * @start: starting cpu index + * + * Note: If no valid cpu found, then nr_cpu_ids is returned. + * + **/ +static inline unsigned int +lpfc_next_online_cpu(const struct cpumask *mask, unsigned int start) +{ + unsigned int cpu_it; + + for_each_cpu_wrap(cpu_it, mask, start) { + if (cpu_online(cpu_it)) + break; + } + + return cpu_it; +} diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 45db19e31..94def7d5b 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -36,8 +35,11 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -55,14 +57,16 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_attr.h" +#ifndef BUILD_BRCMFCOE +#include "lpfc_auth.h" +#endif #define LPFC_DEF_DEVLOSS_TMO 30 #define LPFC_MIN_DEVLOSS_TMO 1 #define LPFC_MAX_DEVLOSS_TMO 255 -#define LPFC_DEF_MRQ_POST 512 -#define LPFC_MIN_MRQ_POST 512 -#define LPFC_MAX_MRQ_POST 2048 +#define LPFC_MAX_INFO_TMP_LEN 100 +#define LPFC_INFO_MORE_STR "\nCould be more info...\n" /* * Write key size should be multiple of 4. If write key is changed @@ -119,6 +123,422 @@ lpfc_jedec_to_ascii(int incr, char hdw[]) return; } +static ssize_t +lpfc_cmf_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_cgn_info *cp = NULL; + struct lpfc_cgn_stat *cgs; + int len = 0; + int cpu; + u64 rcv, total; + char tmp[LPFC_MAX_INFO_TMP_LEN] = {0}; + + if (phba->cgn_i) + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + scnprintf(tmp, sizeof(tmp), + "Congestion Mgmt Info: E2Eattr %d Ver %d " + "CMF %d cnt %d\n", + phba->sli4_hba.pc_sli4_params.E2E_attr, + cp ? cp->cgn_info_version : 0, + phba->sli4_hba.pc_sli4_params.cmf, phba->cmf_timer_cnt); + + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + if (!phba->sli4_hba.pc_sli4_params.cmf) + goto buffer_done; + + switch (phba->cgn_init_reg_signal) { + case LPFC_CGN_SIGNAL_WARN: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:WARN "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_SIGNAL_BOTH: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:WARN|ALARM "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:NONE "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + } + + switch (phba->cgn_init_reg_fpin) { + case LPFC_CGN_FPIN_WARN: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_FPIN_ALARM: + scnprintf(tmp, sizeof(tmp), + "FPIN:ALARM\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_FPIN_BOTH: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN|ALARM\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), + "FPIN:NONE\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + } + + switch (phba->cgn_reg_signal) { + case LPFC_CGN_SIGNAL_WARN: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:WARN "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_SIGNAL_BOTH: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:WARN|ALARM "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:NONE "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + } + + switch (phba->cgn_reg_fpin) { + case LPFC_CGN_FPIN_WARN: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN ACQEcnt:%d\n", phba->cgn_acqe_cnt); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_FPIN_ALARM: + scnprintf(tmp, sizeof(tmp), + "FPIN:ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CGN_FPIN_BOTH: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN|ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), + "FPIN:NONE ACQEcnt:%d\n", phba->cgn_acqe_cnt); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + } + + if (phba->cmf_active_mode != phba->cgn_p.cgn_param_mode) { + switch (phba->cmf_active_mode) { + case LPFC_CFG_OFF: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Off\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CFG_MANAGED: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Managed\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CFG_MONITOR: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Monitor\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Unknown\n"); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + } + } + + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Off "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CFG_MANAGED: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Managed "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + case LPFC_CFG_MONITOR: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Monitor "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + break; + default: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Unknown "); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + } + + scnprintf(tmp, sizeof(tmp), "Ver:%d ACR:%d Scale:%d\n", + phba->cgn_p.cgn_param_version, + phba->cgn_p.cgn_param_acr, + phba->cgn_p.cgn_param_acr_scale); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), "Config: BW:%d Burst:%d " + "ACR: BW:%d(min %d) Burst:%d(min %d)\n", + phba->cgn_p.cgn_param_rxbw, + phba->cgn_p.cgn_param_rxburst, + phba->cgn_p.cgn_param_acr_max_rxbw, + phba->cgn_p.cgn_param_acr_min_rxbw, + phba->cgn_p.cgn_param_acr_max_rxburst, + phba->cgn_p.cgn_param_acr_min_rxburst); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + total = 0; + rcv = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_read(&cgs->total_bytes); + rcv += atomic64_read(&cgs->rcv_bytes); + } + + scnprintf(tmp, sizeof(tmp), + "IObusy:%d NVMEBsyCnt:%d NVMEAbortPendCnt:%d\n" + "Info:%d Bytes: Rcv:x%llx Total:x%llx\n", + atomic_read(&phba->cmf_busy), + phba->nvme_pendq_cnt, + (u32)atomic_read(&phba->nvme_abts_cnt), + phba->cmf_active_info, rcv, total); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), + "Port_speed:%d Link_byte_cnt:%ld " + "Max_byte_per_interval:%ld\n", + lpfc_sli_port_speed_get(phba), + (unsigned long)phba->cmf_link_byte_count, + (unsigned long)phba->cmf_max_bytes_per_interval); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + +buffer_done: + len = strnlen(buf, PAGE_SIZE); + + if (unlikely(len >= (PAGE_SIZE - 1))) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6312 Catching potential buffer " + "overflow > PAGE_SIZE = %lu bytes\n", + PAGE_SIZE); + strlcpy(buf + PAGE_SIZE - 1 - + strnlen(LPFC_INFO_MORE_STR, PAGE_SIZE - 1), + LPFC_INFO_MORE_STR, + strnlen(LPFC_INFO_MORE_STR, PAGE_SIZE - 1) + + 1); + } + return len; +} + +static ssize_t +lpfc_cmf_info_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + uint32_t payload[64]; + int len, status = 0; + int flashit = 0; + unsigned long val; + + /* fpin_warn Simulates a Fabric detected warning + * fpin_alarm Simulates a Fabric detected alarm + * alarm_sig Forces an alarm signal detection + * warn_sig Forces cnt warning signal detections + * alarm_fpin Forces an alarm FPIN detection + * warn_fpin Forces cnt warning FPIN detections + * mode Switches to off(0), managed (1) or monitor(2) mode + * scale Updates ACR scalar parameter (1 - 255) + * acr Updates ACR param conserve(0) moderate(1) severe(2) + * BW Updates rxbw parameter (5% units, 1-20) + * minBurst Updates acr_min_rxburst param (512k units, 0-32) + * minBW Updates acr_min_rxbw param (5% units, 1-20) + * maxBurst Updates acr_max_rxburst param (512k units, 0-32) + * maxBW Updates acr_max_rxbw param (5% units, 1-20) + * wobjmt Delete congestion params from flash + * rxmonitor Dump rxmonitor table + * set_frequency Sets signal frequency (10 sec default) + */ + if ((strncmp(buf, "fpin_warn", strlen("fpin_warn")) == 0)) { + /* Simulate a FPIN warning from Fabric */ + payload[0] = cpu_to_be32(0x16000000); + payload[1] = cpu_to_be32(0x00000014); + payload[2] = cpu_to_be32(0x00020004); + payload[3] = cpu_to_be32(0x0000000c); + payload[4] = cpu_to_be32(0x00030000); + payload[5] = cpu_to_be32(0x0000ea60); + payload[6] = cpu_to_be32(0xf1000000); + len = 28; + lpfc_els_rcv_fpin(vport, payload, len); + } else if ((strncmp(buf, "fpin_alarm", strlen("fpin_alarm")) == 0)) { + /* Simulate a FPIN alarm from Fabric */ + payload[0] = cpu_to_be32(0x16000000); + payload[1] = cpu_to_be32(0x00000014); + payload[2] = cpu_to_be32(0x00020004); + payload[3] = cpu_to_be32(0x0000000c); + payload[4] = cpu_to_be32(0x00030000); + payload[5] = cpu_to_be32(0x0000ea60); + payload[6] = cpu_to_be32(0xf7000000); + len = 28; + lpfc_els_rcv_fpin(vport, payload, len); + } else if ((strncmp(buf, "alarm_sig", strlen("alarm_sig")) == 0)) { + atomic_inc(&phba->cgn_sync_alarm_cnt); + } else if ((strncmp(buf, "warn_sig", strlen("warn_sig")) == 0)) { + val = 0; + status = kstrtoul(buf + 9, 0, &val); + if (!status && val) + atomic_set(&phba->cgn_sync_warn_cnt, (u32)val); + } else if ((strncmp(buf, "alarm_fpin", strlen("alarm_fpin")) == 0)) { + atomic_inc(&phba->cgn_sync_alarm_cnt); + } else if ((strncmp(buf, "warn_fpin", strlen("warn_fpin")) == 0)) { + atomic_inc(&phba->cgn_sync_warn_cnt); + } else if ((strncmp(buf, "mode", strlen("mode")) == 0)) { + val = 0; + status = kstrtoul(buf + 5, 0, &val); + if (status) + return -EINVAL; + switch (val) { + case LPFC_CFG_OFF: + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6326 Disable CMF\n"); + break; + case LPFC_CFG_MANAGED: + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6327 Enable CMF\n"); + break; + case LPFC_CFG_MONITOR: + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6328 Monitor CMF\n"); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6329 Invalid CMF mode: %ld\n", val); + return -EINVAL; + } + phba->cgn_p.cgn_param_mode = val; + flashit = 1; + } else if ((strncmp(buf, "scale", strlen("scale")) == 0)) { + val = 0; + status = kstrtoul(buf + 6, 0, &val); + if (status) + return -EINVAL; + if (val >= LPFC_CFG_LOW_SCALE && + val <= LPFC_CFG_HIGH_SCALE) { + phba->cgn_p.cgn_param_acr_scale = val; + flashit = 1; + status = 0; + } else { + status = -EINVAL; + } + } else if ((strncmp(buf, "acr", strlen("acr")) == 0)) { + val = 0; + status = kstrtoul(buf + 4, 0, &val); + if (status) + return -EINVAL; + if (val >= LPFC_CFG_CONSERVE && + val <= LPFC_CFG_SEVERE) { + phba->cgn_p.cgn_param_acr = val; + flashit = 1; + status = 0; + } else { + status = -EINVAL; + } + } else if ((strncmp(buf, "BW", strlen("BW")) == 0)) { + val = 0; + status = kstrtoul(buf + 3, 0, &val); + if (status) + return -EINVAL; + phba->cgn_p.cgn_param_rxbw = val; + flashit = 1; + } else if ((strncmp(buf, "maxBurst", strlen("maxBurst")) == 0)) { + val = 0; + status = kstrtoul(buf + 9, 0, &val); + if (status) + return -EINVAL; + phba->cgn_p.cgn_param_acr_max_rxburst = val; + flashit = 1; + } else if ((strncmp(buf, "maxBW", strlen("maxBW")) == 0)) { + val = 0; + status = kstrtoul(buf + 6, 0, &val); + if (status) + return -EINVAL; + phba->cgn_p.cgn_param_acr_max_rxbw = val; + flashit = 1; + } else if ((strncmp(buf, "minBurst", strlen("minBurst")) == 0)) { + val = 0; + status = kstrtoul(buf + 9, 0, &val); + if (status) + return -EINVAL; + phba->cgn_p.cgn_param_acr_min_rxburst = val; + flashit = 1; + } else if ((strncmp(buf, "minBW", strlen("minBW")) == 0)) { + val = 0; + status = kstrtoul(buf + 6, 0, &val); + if (status) + return -EINVAL; + phba->cgn_p.cgn_param_acr_min_rxbw = val; + flashit = 1; + } else if ((strncmp(buf, "set_frequency", + strlen("set_frequency")) == 0)) { + val = 0; + status = kstrtoul(buf + 14, 0, &val); + if (status) + return -EINVAL; + lpfc_acqe_cgn_frequency = val; + lpfc_config_cgn_signal(phba); + } else if ((strncmp(buf, "wobjmt", strlen("wobjmt")) == 0)) { + /* Delete the port.cfg store. */ + (void)lpfc_del_object(phba, (char *)LPFC_PORT_CFG_NAME); + } else if ((strncmp(buf, "rxmonitor", strlen("rxmonitor")) == 0)) { + lpfc_cgn_dump_rxmonitor(phba); + } else { + return -EINVAL; + } + + if (flashit) { + if (phba->sli4_hba.pc_sli4_params.cmf) { + /* Update FW flash with driver parameters */ + status = lpfc_write_object + (phba, (char *)LPFC_PORT_CFG_NAME, + (uint32_t *)&phba->cgn_p, + sizeof(struct lpfc_cgn_param)); + if (status <= 0) + status = -EACCES; + } + } + + if (status == 0) + return strlen(buf); + return status; +} /** * lpfc_drvr_version_show - Return the Emulex driver string with version number * @dev: class unused variable. @@ -156,10 +576,13 @@ lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "0\n"); } +#if defined(BUILD_NVME) static ssize_t lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, char *buf) { + int len = 0; +#if (IS_ENABLED(CONFIG_NVME_FC)) struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = shost_priv(shost); struct lpfc_hba *phba = vport->phba; @@ -174,8 +597,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, uint64_t totin, totout, tot; char *statep; int i; - int len = 0; - char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0}; + char tmp[LPFC_MAX_INFO_TMP_LEN] = {0}; if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n"); @@ -193,6 +615,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, statep = "REGISTERED"; else statep = "INIT"; + scnprintf(tmp, sizeof(tmp), "NVME Target Enabled State %s\n", statep); @@ -332,6 +755,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, phba->sli4_hba.nvmet_io_wait_total, tot); strlcat(buf, tmp, PAGE_SIZE); + goto buffer_done; } @@ -520,14 +944,19 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, "overflow > PAGE_SIZE = %lu bytes\n", PAGE_SIZE); strlcpy(buf + PAGE_SIZE - 1 - - strnlen(LPFC_NVME_INFO_MORE_STR, PAGE_SIZE - 1), - LPFC_NVME_INFO_MORE_STR, - strnlen(LPFC_NVME_INFO_MORE_STR, PAGE_SIZE - 1) + strnlen(LPFC_INFO_MORE_STR, PAGE_SIZE - 1), + LPFC_INFO_MORE_STR, + strnlen(LPFC_INFO_MORE_STR, PAGE_SIZE - 1) + 1); } +#else + len = scnprintf(buf, PAGE_SIZE, + "NVME not Supported in kernel\n"); +#endif return len; } +#endif static ssize_t lpfc_scsi_stat_show(struct device *dev, struct device_attribute *attr, @@ -587,17 +1016,29 @@ lpfc_bg_info_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + int len = 0; if (phba->cfg_enable_bg) { if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - return scnprintf(buf, PAGE_SIZE, - "BlockGuard Enabled\n"); + len += scnprintf(buf, PAGE_SIZE, + "BlockGuard Enabled\n"); else - return scnprintf(buf, PAGE_SIZE, + len += scnprintf(buf, PAGE_SIZE, "BlockGuard Not Supported\n"); - } else - return scnprintf(buf, PAGE_SIZE, + } else { + len += scnprintf(buf, PAGE_SIZE, "BlockGuard Disabled\n"); + } + + if (phba->cfg_external_dif) { + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) + len += scnprintf(buf + len, PAGE_SIZE, + "External DIF Enabled\n"); + else + len += scnprintf(buf + len, PAGE_SIZE, + "External DIF Not Supported\n"); + } + return len; } static ssize_t @@ -650,7 +1091,7 @@ lpfc_info_show(struct device *dev, struct device_attribute *attr, { struct Scsi_Host *host = class_to_shost(dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", lpfc_info(host)); + return scnprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); } /** @@ -669,7 +1110,7 @@ lpfc_serialnum_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%s\n", phba->SerialNumber); + return scnprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); } /** @@ -691,7 +1132,7 @@ lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%d\n", phba->temp_sensor_support); + return scnprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); } /** @@ -710,7 +1151,7 @@ lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelDesc); + return scnprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); } /** @@ -729,7 +1170,7 @@ lpfc_modelname_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelName); + return scnprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); } /** @@ -748,7 +1189,7 @@ lpfc_programtype_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ProgramType); + return scnprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); } /** @@ -786,7 +1227,7 @@ lpfc_vportnum_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return scnprintf(buf, PAGE_SIZE, "%s\n", phba->Port); + return scnprintf(buf, PAGE_SIZE, "%s\n",phba->Port); } /** @@ -864,7 +1305,7 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, if (phba->sli_rev < LPFC_SLI_REV4) return scnprintf(buf, PAGE_SIZE, "%s\n", - phba->OptionROMVersion); + phba->OptionROMVersion); lpfc_decode_firmware_rev(phba, fwrev, 1); return scnprintf(buf, PAGE_SIZE, "%s\n", fwrev); @@ -898,20 +1339,20 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: if (phba->hba_flag & LINK_DISABLED) - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Link Down - User disabled\n"); else - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - len += scnprintf(buf + len, PAGE_SIZE-len, "Link Up - "); + len += scnprintf(buf + len, PAGE_SIZE - len, "Link Up - "); switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Configuring Link\n"); break; case LPFC_FDISC: @@ -926,12 +1367,12 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, break; case LPFC_VPORT_READY: len += scnprintf(buf + len, PAGE_SIZE - len, - "Ready\n"); + "Ready\n"); break; case LPFC_VPORT_FAILED: len += scnprintf(buf + len, PAGE_SIZE - len, - "Failed\n"); + "Failed\n"); break; case LPFC_VPORT_UNKNOWN: @@ -940,21 +1381,21 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, break; } if (phba->sli.sli_flag & LPFC_MENLO_MAINT) - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, " Menlo Maint Mode\n"); else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { if (vport->fc_flag & FC_PUBLIC_LOOP) - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, " Public Loop\n"); else - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, " Private Loop\n"); } else { if (vport->fc_flag & FC_FABRIC) - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, " Fabric\n"); else - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, " Point-2-Point\n"); } } @@ -1071,10 +1512,10 @@ lpfc_link_state_store(struct device *dev, struct device_attribute *attr, if ((strncmp(buf, "up", sizeof("up") - 1) == 0) && (phba->link_state == LPFC_LINK_DOWN)) - status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + status = phba->lpfc_hba_init_link(phba); else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) && (phba->link_state >= LPFC_LINK_UP)) - status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT); + status = phba->lpfc_hba_down_link(phba); if (status == 0) return strlen(buf); @@ -1119,7 +1560,7 @@ lpfc_num_discovered_ports_show(struct device *dev, * -EIO error sending the mailbox command * zero for success **/ -static int +int lpfc_issue_lip(struct Scsi_Host *shost) { struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; @@ -1185,7 +1626,7 @@ lpfc_emptyq_wait(struct lpfc_hba *phba, struct list_head *q, spinlock_t *lock) lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0466 %s %s\n", "Outstanding IO when ", - "bringing Adapter offline\n"); + "waiting for IO to drain\n"); return 0; } spin_lock_irq(lock); @@ -1352,8 +1793,14 @@ lpfc_reset_pci_bus(struct lpfc_hba *phba) } } +#if defined(BUILD_RHEL8) || defined(BUILD_SLES15SP) || \ +defined(BUILD_SLES12SP5) || (KERNEL_VERSION(4, 18, 0) < LINUX_VERSION_CODE) /* Issue PCI bus reset */ res = pci_reset_bus(pdev); +#else + /* Issue PCI bus reset */ + res = pci_reset_bus(pdev->bus); +#endif if (res) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "8350 PCI reset bus failed: %d\n", res); @@ -1475,8 +1922,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) int i; msleep(100); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0)) + return -EIO; /* verify if privileged for the request operation */ if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) && @@ -1486,8 +1934,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) /* wait for the SLI port firmware ready after firmware reset */ for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) { msleep(10); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0)) + continue; if (!bf_get(lpfc_sliport_status_err, &portstat_reg)) continue; if (!bf_get(lpfc_sliport_status_rn, &portstat_reg)) @@ -1691,7 +2140,8 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "0071 Set trunk mode failed with status: %d", rc); - mempool_free(mbox, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); return 0; } @@ -1791,6 +2241,8 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, else if (strncmp(buf, "pci_bus_reset", sizeof("pci_bus_reset") - 1) == 0) status = lpfc_reset_pci_bus(phba); + else if (strncmp(buf, "heartbeat", sizeof("heartbeat") - 1) == 0) + lpfc_issue_hb_tmo(phba); else if (strncmp(buf, "trunk", sizeof("trunk") - 1) == 0) status = lpfc_set_trunking(phba, (char *)buf + sizeof("trunk")); else @@ -2227,66 +2679,6 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } -/** - * lpfc_fips_level_show - Return the current FIPS level for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_level_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); -} - -/** - * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); -} - -/** - * lpfc_dss_show - Return the current state of dss and the configured state - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_dss_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n", - (phba->cfg_enable_dss) ? "Enabled" : "Disabled", - (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ? - "" : "Not "); -} - /** * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions * @dev: class converted to a Scsi_host structure. @@ -2313,11 +2705,6 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); } -static inline bool lpfc_rangecheck(uint val, uint min, uint max) -{ - return val >= min && val <= max; -} - /** * lpfc_enable_bbcr_set: Sets an attribute value. * @phba: pointer the the adapter structure. @@ -2430,8 +2817,9 @@ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ return 0;\ }\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "0449 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ + "0449 "LPFC_DRIVER_NAME"_"#attr" attribute " \ + "cannot be set to %d, allowed range is [" \ + #minval", "#maxval"]\n", val); \ phba->cfg_##attr = default;\ return -EINVAL;\ } @@ -2462,14 +2850,15 @@ lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \ { \ if (lpfc_rangecheck(val, minval, maxval)) {\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "3052 lpfc_" #attr " changed from %d to %d\n", \ - phba->cfg_##attr, val); \ + "3052 "LPFC_DRIVER_NAME"_" #attr " changed from " \ + "%d to %d\n", phba->cfg_##attr, val); \ phba->cfg_##attr = val;\ return 0;\ }\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "0450 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ + "0450 "LPFC_DRIVER_NAME"_"#attr" attribute " \ + "cannot be set to %d, allowed range is [" \ + #minval", "#maxval"]\n", val); \ return -EINVAL;\ } @@ -2589,8 +2978,9 @@ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ return 0;\ }\ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "0423 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ + "0423 "LPFC_DRIVER_NAME"_"#attr" attribute " \ + "cannot be set to %d, allowed range is [" \ + #minval", "#maxval"]\n", val); \ vport->cfg_##attr = default;\ return -EINVAL;\ } @@ -2618,7 +3008,7 @@ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ { \ if (lpfc_rangecheck(val, minval, maxval)) {\ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "3053 lpfc_" #attr \ + "3053 "LPFC_DRIVER_NAME"_" #attr \ " changed from %d (x%x) to %d (x%x)\n", \ vport->cfg_##attr, vport->cfg_##attr, \ val, val); \ @@ -2626,8 +3016,9 @@ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ return 0;\ }\ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "0424 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ + "0424 "LPFC_DRIVER_NAME"_"#attr" attribute " \ + "cannot be set to %d, allowed range is [" \ + #minval", "#maxval"]\n", val); \ return -EINVAL;\ } @@ -2667,7 +3058,9 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ } +#ifdef BUILD_NVME static DEVICE_ATTR(nvme_info, 0444, lpfc_nvme_info_show, NULL); +#endif static DEVICE_ATTR(scsi_stat, 0444, lpfc_scsi_stat_show, NULL); static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL); static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL); @@ -2689,8 +3082,8 @@ static DEVICE_ATTR(num_discovered_ports, S_IRUGO, lpfc_num_discovered_ports_show, NULL); static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL); static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); -static DEVICE_ATTR_RO(lpfc_drvr_version); -static DEVICE_ATTR_RO(lpfc_enable_fip); +static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); +static DEVICE_ATTR(lpfc_enable_fip, S_IRUGO, lpfc_enable_fip_show, NULL); static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, lpfc_board_mode_show, lpfc_board_mode_store); static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); @@ -2701,16 +3094,15 @@ static DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL); static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); -static DEVICE_ATTR_RO(lpfc_temp_sensor); -static DEVICE_ATTR_RO(lpfc_fips_level); -static DEVICE_ATTR_RO(lpfc_fips_rev); -static DEVICE_ATTR_RO(lpfc_dss); -static DEVICE_ATTR_RO(lpfc_sriov_hw_max_virtfn); +static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL); +static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, + lpfc_sriov_hw_max_virtfn_show, NULL); static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, NULL); +static DEVICE_ATTR(cmf_info, S_IRUGO | S_IWUSR, lpfc_cmf_info_show, + lpfc_cmf_info_store); -static char *lpfc_soft_wwn_key = "C99G71SL8032A"; #define WWN_SZ 8 /** * lpfc_wwn_set - Convert string to the 8 byte WWN value. @@ -2754,228 +3146,6 @@ lpfc_wwn_set(const char *buf, size_t cnt, char wwn[]) } return 0; } -/** - * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string lpfc_soft_wwn_key. - * @count: must be size of lpfc_soft_wwn_key. - * - * Returns: - * -EINVAL if the buffer does not contain lpfc_soft_wwn_key - * length of buf indicates success - **/ -static ssize_t -lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - unsigned int cnt = count; - uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level; - u32 *fawwpn_key = (uint32_t *)&vport->fc_sparam.un.vendorVersion[0]; - - /* - * We're doing a simple sanity check for soft_wwpn setting. - * We require that the user write a specific key to enable - * the soft_wwpn attribute to be settable. Once the attribute - * is written, the enable key resets. If further updates are - * desired, the key must be written again to re-enable the - * attribute. - * - * The "key" is not secret - it is a hardcoded string shown - * here. The intent is to protect against the random user or - * application that is just writing attributes. - */ - if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0051 "LPFC_DRIVER_NAME" soft wwpn can not" - " be enabled: fawwpn is enabled\n"); - return -EINVAL; - } - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if ((cnt != strlen(lpfc_soft_wwn_key)) || - (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) - return -EINVAL; - - phba->soft_wwn_enable = 1; - - dev_printk(KERN_WARNING, &phba->pcidev->dev, - "lpfc%d: soft_wwpn assignment has been enabled.\n", - phba->brd_no); - dev_printk(KERN_WARNING, &phba->pcidev->dev, - " The soft_wwpn feature is not supported by Broadcom."); - - return count; -} -static DEVICE_ATTR_WO(lpfc_soft_wwn_enable); - -/** - * lpfc_soft_wwpn_show - Return the cfg soft ww port name of the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwpn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwpn); -} - -/** - * lpfc_soft_wwpn_store - Set the ww port name of the adapter - * @dev class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: contains the wwpn in hexadecimal. - * @count: number of wwpn bytes in buf - * - * Returns: - * -EACCES hba reset not enabled, adapter over temp - * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid - * -EIO error taking adapter offline or online - * value of count on success - **/ -static ssize_t -lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct completion online_compl; - int stat1 = 0, stat2 = 0; - unsigned int cnt = count; - u8 wwpn[WWN_SZ]; - int rc; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - spin_lock_irq(&phba->hbalock); - if (phba->over_temp_state == HBA_OVER_TEMP) { - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - spin_unlock_irq(&phba->hbalock); - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - - /* lock setting wwpn, wwnn down */ - phba->soft_wwn_enable = 0; - - rc = lpfc_wwn_set(buf, cnt, wwpn); - if (rc) { - /* not able to set wwpn, unlock it */ - phba->soft_wwn_enable = 1; - return rc; - } - - phba->cfg_soft_wwpn = wwn_to_u64(wwpn); - fc_host_port_name(shost) = phba->cfg_soft_wwpn; - if (phba->cfg_soft_wwnn) - fc_host_node_name(shost) = phba->cfg_soft_wwnn; - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); - - stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - if (stat1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0463 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat1); - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &stat2, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - if (stat2) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0464 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat2); - return (stat1 || stat2) ? -EIO : count; -} -static DEVICE_ATTR_RW(lpfc_soft_wwpn); - -/** - * lpfc_soft_wwnn_show - Return the cfg soft ww node name for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwnn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return scnprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwnn); -} - -/** - * lpfc_soft_wwnn_store - sets the ww node name of the adapter - * @cdev: class device that is converted into a Scsi_host. - * @buf: contains the ww node name in hexadecimal. - * @count: number of wwnn bytes in buf. - * - * Returns: - * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid - * value of count on success - **/ -static ssize_t -lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - unsigned int cnt = count; - u8 wwnn[WWN_SZ]; - int rc; - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - - rc = lpfc_wwn_set(buf, cnt, wwnn); - if (rc) { - /* Allow wwnn to be set many times, as long as the enable - * is set. However, once the wwpn is set, everything locks. - */ - return rc; - } - - phba->cfg_soft_wwnn = wwn_to_u64(wwnn); - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: soft_wwnn set. Value will take effect upon " - "setting of the soft_wwpn\n", phba->brd_no); - - return count; -} -static DEVICE_ATTR_RW(lpfc_soft_wwnn); /** * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for @@ -3099,10 +3269,7 @@ lpfc_oas_priority_store(struct device *dev, struct device_attribute *attr, if (ret || (val > 0x7f)) return -EINVAL; - if (val) - phba->cfg_oas_priority = (uint8_t)val; - else - phba->cfg_oas_priority = phba->cfg_XLanePriority; + phba->cfg_oas_priority = (uint8_t)val; return count; } static DEVICE_ATTR(lpfc_xlane_priority, S_IRUGO | S_IWUSR, @@ -3412,7 +3579,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, if (oas_lun != NOT_OAS_ENABLED_LUN) phba->cfg_oas_flags |= OAS_LUN_VALID; - len += scnprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun); + len += scnprintf(buf + len, PAGE_SIZE - len, "0x%llx", oas_lun); return len; } @@ -3458,9 +3625,6 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, return -EINVAL; pri = phba->cfg_oas_priority; - if (pri == 0) - pri = phba->cfg_XLanePriority; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx " "priority 0x%x with oas state %d\n", @@ -3479,12 +3643,14 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(lpfc_xlane_lun, S_IRUGO | S_IWUSR, lpfc_oas_lun_show, lpfc_oas_lun_store); +#ifdef BUILD_NVME int lpfc_enable_nvmet_cnt; unsigned long long lpfc_enable_nvmet[LPFC_NVMET_MAX_PORTS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; module_param_array(lpfc_enable_nvmet, ullong, &lpfc_enable_nvmet_cnt, 0444); MODULE_PARM_DESC(lpfc_enable_nvmet, "Enable HBA port(s) WWPN as a NVME Target"); +#endif static int lpfc_poll = 0; module_param(lpfc_poll, int, S_IRUGO); @@ -3493,7 +3659,8 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:" " 1 - poll with interrupts enabled" " 3 - poll and disable FCP ring interrupts"); -static DEVICE_ATTR_RW(lpfc_poll); +static DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR, + lpfc_poll_show, lpfc_poll_store); int lpfc_no_hba_reset_cnt; unsigned long lpfc_no_hba_reset[MAX_HBAS_NO_RESET] = { @@ -3513,6 +3680,11 @@ LPFC_ATTR_R(enable_npiv, 1, 0, 1, LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2, "FCF Fast failover=1 Priority failover=2"); +#ifndef NO_APEX +LPFC_ATTR_RW(enable_fcp_priority, 0, 0, 1, + "Enable/disable, (1,0) FCP Priority"); +#endif + /* # lpfc_enable_rrq: Track XRI/OXID reuse after IO failures # 0x0 = disabled, XRI/OXID use not tracked. @@ -3532,6 +3704,31 @@ LPFC_ATTR_R(enable_rrq, 2, 0, 2, LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK, LPFC_DELAY_INIT_LINK_INDEFINITELY, "Suppress Link Up at initialization"); + +static ssize_t +lpfc_pls_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + phba->sli4_hba.pc_sli4_params.pls); +} +static DEVICE_ATTR(pls, S_IRUGO, + lpfc_pls_show, NULL); + +static ssize_t +lpfc_pt_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + (phba->hba_flag & HBA_PERSISTENT_TOPO) ? 1 : 0); +} +static DEVICE_ATTR(pt, S_IRUGO, + lpfc_pt_show, NULL); + /* # lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS # 1 - (1024) @@ -3579,9 +3776,6 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(txcmplq_hw, S_IRUGO, lpfc_txcmplq_hw_show, NULL); -LPFC_ATTR_R(iocb_cnt, 2, 1, 5, - "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs"); - /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear # until the timer expires. Value range is [0,255]. Default value is 30. @@ -3633,9 +3827,9 @@ lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val) vport->cfg_nodev_tmo = vport->cfg_devloss_tmo; if (val != LPFC_DEF_DEVLOSS_TMO) lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0407 Ignoring lpfc_nodev_tmo module " - "parameter because lpfc_devloss_tmo " - "is set.\n"); + "0407 Ignoring "LPFC_DRIVER_NAME + "_nodev_tmo module parameter because " + LPFC_DRIVER_NAME"devloss_tmo is set.\n"); return 0; } @@ -3645,8 +3839,8 @@ lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val) return 0; } lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0400 lpfc_nodev_tmo attribute cannot be set to" - " %d, allowed range is [%d, %d]\n", + "0400 "LPFC_DRIVER_NAME"_nodev_tmo attribute cannot " + "be set to %d, allowed range is [%d, %d]\n", val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); vport->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO; return -EINVAL; @@ -3664,7 +3858,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) { struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; -#if (IS_ENABLED(CONFIG_NVME_FC)) +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) struct lpfc_nvme_rport *rport; struct nvme_fc_remote_port *remoteport = NULL; #endif @@ -3676,7 +3870,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) continue; if (ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; -#if (IS_ENABLED(CONFIG_NVME_FC)) +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) spin_lock(&vport->phba->hbalock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) @@ -3711,31 +3905,27 @@ lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val) if (vport->dev_loss_tmo_changed || (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0401 Ignoring change to lpfc_nodev_tmo " - "because lpfc_devloss_tmo is set.\n"); + "0401 Ignoring change to "LPFC_DRIVER_NAME + "_nodev_tmo because devloss_tmo is set.\n"); return 0; } if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { vport->cfg_nodev_tmo = val; vport->cfg_devloss_tmo = val; - /* - * For compat: set the fc_host dev loss so new rports - * will get the value. - */ - fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; lpfc_update_rport_devloss_tmo(vport); return 0; } lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0403 lpfc_nodev_tmo attribute cannot be set to " - "%d, allowed range is [%d, %d]\n", + "0403 "LPFC_DRIVER_NAME"_nodev_tmo attribute cannot " + "be set to %d, allowed range is [%d, %d]\n", val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); return -EINVAL; } lpfc_vport_param_store(nodev_tmo) -static DEVICE_ATTR_RW(lpfc_nodev_tmo); +static DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR, + lpfc_nodev_tmo_show, lpfc_nodev_tmo_store); /* # lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that @@ -3771,20 +3961,20 @@ lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val) vport->cfg_nodev_tmo = val; vport->cfg_devloss_tmo = val; vport->dev_loss_tmo_changed = 1; - fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; lpfc_update_rport_devloss_tmo(vport); return 0; } lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0404 lpfc_devloss_tmo attribute cannot be set to " - "%d, allowed range is [%d, %d]\n", + "0404 "LPFC_DRIVER_NAME"_devloss_tmo attribute " + "cannot be set to %d, allowed range is [%d, %d]\n", val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); return -EINVAL; } lpfc_vport_param_store(devloss_tmo) -static DEVICE_ATTR_RW(lpfc_devloss_tmo); +static DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR, + lpfc_devloss_tmo_show, lpfc_devloss_tmo_store); /* * lpfc_suppress_rsp: Enable suppress rsp feature is firmware supports it @@ -3795,6 +3985,7 @@ static DEVICE_ATTR_RW(lpfc_devloss_tmo); LPFC_ATTR_R(suppress_rsp, 1, 0, 1, "Enable suppress rsp feature is firmware supports it"); +#ifdef BUILD_NVME /* * lpfc_nvmet_mrq: Specify number of RQ pairs for processing NVMET cmds * lpfc_nvmet_mrq = 0 driver will calcualte optimal number of RQ pairs @@ -3814,7 +4005,9 @@ LPFC_ATTR_R(nvmet_mrq_post, LPFC_NVMET_RQE_DEF_POST, LPFC_NVMET_RQE_MIN_POST, LPFC_NVMET_RQE_DEF_COUNT, "Specify number of RQ buffers to initially post"); +#endif +#ifdef BUILD_NVME /* * lpfc_enable_fc4_type: Defines what FC4 types are supported. * Supported Values: 1 - register just FCP @@ -3824,6 +4017,12 @@ LPFC_ATTR_R(nvmet_mrq_post, LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH, LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH, "Enable FC4 Protocol support - FCP / NVME"); +#else +LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_FCP, + LPFC_ENABLE_FCP, LPFC_ENABLE_FCP, + "Enable FC4 Protocol support - FCP"); + +#endif /* # lpfc_log_verbose: Only turn this flag on if you are willing to risk being @@ -3844,19 +4043,84 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1, /* # lun_queue_depth: This parameter is used to limit the number of outstanding # commands per FCP LUN. Value range is [1,512]. Default value is 30. -# If this parameter value is greater than 1/8th the maximum number of exchanges -# supported by the HBA port, then the lun queue depth will be reduced to -# 1/8th the maximum number of exchanges. */ -LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512, - "Max number of FCP commands we can queue to a specific LUN"); +static u16 lpfc_lun_queue_depth = LPFC_DEF_LUN_QDEPTH; +module_param(lpfc_lun_queue_depth, ushort, 0644); +MODULE_PARM_DESC(lpfc_lun_queue_depth, + "Max number of FCP commands we can queue to a specific LUN"); +lpfc_vport_param_show(lun_queue_depth); +lpfc_vport_param_init(lun_queue_depth, LPFC_DEF_LUN_QDEPTH, LPFC_MIN_LUN_QDEPTH, + LPFC_MAX_LUN_QDEPTH); + +static ssize_t +lpfc_lun_queue_depth_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct scsi_device *sdev; + struct lpfc_cgn_info *cp; + u16 new_queue_depth; + u32 crc; + int rc; + + rc = kstrtou16(buf, 0, &new_queue_depth); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "4385 lpfc_lun_queue_depth: failed to convert " + "\"%s\" to u16 (%d)\n", + buf, rc); + return -EINVAL; + } + + /* Check allowed range */ + if (new_queue_depth < LPFC_MIN_LUN_QDEPTH || + new_queue_depth > LPFC_MAX_LUN_QDEPTH) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "4386 lpfc_lun_queue_depth: %d outside of " + "allowed range [%u, %u]\n", + new_queue_depth, LPFC_MIN_LUN_QDEPTH, + LPFC_MAX_LUN_QDEPTH); + return -EINVAL; + } + + /* Check if previously set same value */ + if (new_queue_depth == vport->cfg_lun_queue_depth) + goto buffer_done; + + /* Store for future calls to slave_configure */ + vport->cfg_lun_queue_depth = new_queue_depth; + + /* Change all the current LUNs' queue depths */ + shost_for_each_device(sdev, shost) { + sdev->max_queue_depth = new_queue_depth; + scsi_change_queue_depth(sdev, new_queue_depth); + } + + if (phba->cgn_i) { + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + new_queue_depth = (uint16_t)(phba->pport->cfg_lun_queue_depth); + + /* The location of cgn_info (cp) is registered with + * firmware and the contents maintained in LE format. + */ + cp->cgn_lunq = cpu_to_le16(new_queue_depth); + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + } +buffer_done: + return strlen(buf); +} +static DEVICE_ATTR_RW(lpfc_lun_queue_depth); /* # tgt_queue_depth: This parameter is used to limit the number of outstanding # commands per target port. Value range is [10,65535]. Default value is 65535. */ static uint lpfc_tgt_queue_depth = LPFC_MAX_TGT_QDEPTH; -module_param(lpfc_tgt_queue_depth, uint, 0444); +module_param(lpfc_tgt_queue_depth, uint, S_IRUGO); MODULE_PARM_DESC(lpfc_tgt_queue_depth, "Set max Target queue depth"); lpfc_vport_param_show(tgt_queue_depth); lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH, @@ -3959,9 +4223,9 @@ lpfc_restrict_login_init(struct lpfc_vport *vport, int val) { if (val < 0 || val > 1) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0422 lpfc_restrict_login attribute cannot " - "be set to %d, allowed range is [0, 1]\n", - val); + "0422 "LPFC_DRIVER_NAME"_restrict_login " + "attribute cannot be set to %d, allowed " + "range is [0, 1]\n", val); vport->cfg_restrict_login = 1; return -EINVAL; } @@ -3994,16 +4258,16 @@ lpfc_restrict_login_set(struct lpfc_vport *vport, int val) { if (val < 0 || val > 1) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0425 lpfc_restrict_login attribute cannot " - "be set to %d, allowed range is [0, 1]\n", - val); + "0425 "LPFC_DRIVER_NAME"_restrict_login " + "attribute cannot be set to %d, allowed " + "range is [0, 1]\n", val); vport->cfg_restrict_login = 1; return -EINVAL; } if (vport->port_type == LPFC_PHYSICAL_PORT && val != 0) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0468 lpfc_restrict_login must be 0 for " - "Physical ports.\n"); + "0468 "LPFC_DRIVER_NAME"_restrict_login " + "must be 0 for Physical ports.\n"); vport->cfg_restrict_login = 0; return 0; } @@ -4011,7 +4275,8 @@ lpfc_restrict_login_set(struct lpfc_vport *vport, int val) return 0; } lpfc_vport_param_store(restrict_login); -static DEVICE_ATTR_RW(lpfc_restrict_login); +static DEVICE_ATTR(lpfc_restrict_login, S_IRUGO | S_IWUSR, + lpfc_restrict_login_show, lpfc_restrict_login_store); /* # Some disk devices have a "select ID" or "select Target" capability. @@ -4095,8 +4360,16 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, val); return -EINVAL; } - if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || - phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && + /* + * The 'topology' is not a configurable parameter if : + * - persistent topology enabled + * - G7/G6 with no private loop support + */ + + if ((phba->hba_flag & HBA_PERSISTENT_TOPO || + (!phba->sli4_hba.pc_sli4_params.pls && + (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || + phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC))) && val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "3114 Loop mode not supported\n"); @@ -4126,7 +4399,8 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, } lpfc_param_show(topology) -static DEVICE_ATTR_RW(lpfc_topology); +static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, + lpfc_topology_show, lpfc_topology_store); /** * lpfc_static_vport_show: Read callback function for @@ -4156,7 +4430,8 @@ lpfc_static_vport_show(struct device *dev, struct device_attribute *attr, /* * Sysfs attribute to control the statistical data collection. */ -static DEVICE_ATTR_RO(lpfc_static_vport); +static DEVICE_ATTR(lpfc_static_vport, S_IRUGO, + lpfc_static_vport_show, NULL); /** * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file @@ -4383,7 +4658,8 @@ lpfc_stat_data_ctrl_show(struct device *dev, struct device_attribute *attr, /* * Sysfs attribute to control the statistical data collection. */ -static DEVICE_ATTR_RW(lpfc_stat_data_ctrl); +static DEVICE_ATTR(lpfc_stat_data_ctrl, S_IRUGO | S_IWUSR, + lpfc_stat_data_ctrl_show, lpfc_stat_data_ctrl_store); /* * lpfc_drvr_stat_data: sysfs attr to get driver statistical data. @@ -4475,7 +4751,7 @@ sysfs_drvr_stat_data_read(struct file *filp, struct kobject *kobj, static struct bin_attribute sysfs_drvr_stat_data_attr = { .attr = { - .name = "lpfc_drvr_stat_data", + .name = LPFC_DRIVER_NAME"_drvr_stat_data", .mode = S_IRUSR, }, .size = LPFC_MAX_TARGET * MAX_STAT_DATA_SIZE_PER_TARGET, @@ -4618,7 +4894,7 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val) { if (val >= LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3111 lpfc_link_speed of %d cannot " + "3111 "LPFC_DRIVER_NAME"_link_speed of %d cannot " "support loop mode, setting topology to default.\n", val); phba->cfg_topology = 0; @@ -4645,7 +4921,8 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val) } } -static DEVICE_ATTR_RW(lpfc_link_speed); +static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, + lpfc_link_speed_show, lpfc_link_speed_store); /* # lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER) @@ -4738,7 +5015,8 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, return rc; } -static DEVICE_ATTR_RW(lpfc_aer_support); +static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR, + lpfc_aer_support_show, lpfc_aer_support_store); /** * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device @@ -4750,8 +5028,8 @@ static DEVICE_ATTR_RW(lpfc_aer_support); * Description: * If the @buf contains 1 and the device currently has the AER support * enabled, then invokes the kernel AER helper routine - * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable - * error status register. + * pci_aer_clear_nonfatal_status to clean up the uncorrectable error + * status register. * * Notes: * @@ -4776,7 +5054,11 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, return -EINVAL; if (phba->hba_flag & HBA_AER_ENABLED) +#if defined(BUILD_SLES15SP2) || defined(BUILD_RHEL83) + rc = pci_aer_clear_nonfatal_status(phba->pcidev); +#else rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev); +#endif if (rc == 0) return strlen(buf); @@ -4885,7 +5167,8 @@ LPFC_ATTR(sriov_nr_virtfn, LPFC_DEF_VFN_PER_PFN, 0, LPFC_MAX_VFN_PER_PFN, "Enable PCIe device SR-IOV virtual fn"); lpfc_param_show(sriov_nr_virtfn) -static DEVICE_ATTR_RW(lpfc_sriov_nr_virtfn); +static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR, + lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store); /** * lpfc_request_firmware_store - Request for Linux generic firmware upgrade @@ -4995,8 +5278,8 @@ lpfc_force_rscn_store(struct device *dev, struct device_attribute *attr, * * Value range is any ascii value */ -static int lpfc_force_rscn; -module_param(lpfc_force_rscn, int, 0644); +static int lpfc_force_rscn = 0; +module_param(lpfc_force_rscn, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(lpfc_force_rscn, "Force an RSCN to be sent to all remote NPorts"); lpfc_param_show(force_rscn) @@ -5014,6 +5297,7 @@ lpfc_force_rscn_init(struct lpfc_hba *phba, int val) { return 0; } + static DEVICE_ATTR_RW(lpfc_force_rscn); /** @@ -5127,14 +5411,25 @@ lpfc_fcp_imax_init(struct lpfc_hba *phba, int val) } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3016 lpfc_fcp_imax: %d out of range, using default\n", - val); + "3016 "LPFC_DRIVER_NAME"_fcp_imax: " + "%d out of range, using default\n", val); phba->cfg_fcp_imax = LPFC_DEF_IMAX; return 0; } -static DEVICE_ATTR_RW(lpfc_fcp_imax); +static DEVICE_ATTR(lpfc_fcp_imax, S_IRUGO | S_IWUSR, + lpfc_fcp_imax_show, lpfc_fcp_imax_store); + +/* + * lpfc_cq_poll_threshold: Set the threshold of CQE completions in a + * single handler call which should request a polled completion rather + * than re-enabling interrupts. + */ +LPFC_ATTR_RW(cq_poll_threshold, LPFC_CQ_DEF_THRESHOLD_TO_POLL, + LPFC_CQ_MIN_THRESHOLD_TO_POLL, + LPFC_CQ_MAX_THRESHOLD_TO_POLL, + "CQE Processing Threshold to enable Polling"); /** * lpfc_cq_max_proc_limit_store @@ -5204,16 +5499,6 @@ MODULE_PARM_DESC(lpfc_cq_max_proc_limit, "CQ processing"); lpfc_param_show(cq_max_proc_limit) -/* - * lpfc_cq_poll_threshold: Set the threshold of CQE completions in a - * single handler call which should request a polled completion rather - * than re-enabling interrupts. - */ -LPFC_ATTR_RW(cq_poll_threshold, LPFC_CQ_DEF_THRESHOLD_TO_POLL, - LPFC_CQ_MIN_THRESHOLD_TO_POLL, - LPFC_CQ_MAX_THRESHOLD_TO_POLL, - "CQE Processing Threshold to enable Polling"); - /** * lpfc_cq_max_proc_limit_init - Set the initial cq max_proc_limit * @phba: lpfc_hba pointer. @@ -5249,7 +5534,8 @@ lpfc_cq_max_proc_limit_init(struct lpfc_hba *phba, int val) return 0; } -static DEVICE_ATTR_RW(lpfc_cq_max_proc_limit); +static DEVICE_ATTR(lpfc_cq_max_proc_limit, S_IRUGO | S_IWUSR, + lpfc_cq_max_proc_limit_show, lpfc_cq_max_proc_limit_store); /** * lpfc_state_show - Display current driver CPU affinity @@ -5275,12 +5561,12 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, switch (phba->cfg_fcp_cpu_map) { case 0: - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "fcp_cpu_map: No mapping (%d)\n", phba->cfg_fcp_cpu_map); return len; case 1: - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "fcp_cpu_map: HBA centric mapping (%d): " "%d of %d CPUs online from %d possible CPUs\n", phba->cfg_fcp_cpu_map, num_online_cpus(), @@ -5289,15 +5575,15 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, break; } - while (phba->sli4_hba.curr_disp_cpu < - phba->sli4_hba.num_possible_cpu) { + while (phba->sli4_hba.curr_disp_cpu < phba->sli4_hba.num_possible_cpu) { cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu]; + /* margin should fit in this and the truncated message */ if (!cpu_present(phba->sli4_hba.curr_disp_cpu)) len += scnprintf(buf + len, PAGE_SIZE - len, "CPU %02d not present\n", phba->sli4_hba.curr_disp_cpu); - else if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) { + else if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY) len += scnprintf( buf + len, PAGE_SIZE - len, @@ -5310,10 +5596,10 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, else len += scnprintf( buf + len, PAGE_SIZE - len, - "CPU %02d EQ %04d hdwq %04d " + "CPU %02d EQ None hdwq %04d " "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, - cpup->eq, cpup->hdwq, cpup->phys_id, + cpup->hdwq, cpup->phys_id, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); @@ -5328,7 +5614,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN), - cpup->irq); + lpfc_get_irq(cpup->eq)); else len += scnprintf( buf + len, PAGE_SIZE - len, @@ -5339,7 +5625,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN), - cpup->irq); + lpfc_get_irq(cpup->eq)); } phba->sli4_hba.curr_disp_cpu++; @@ -5420,14 +5706,15 @@ lpfc_fcp_cpu_map_init(struct lpfc_hba *phba, int val) } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3326 lpfc_fcp_cpu_map: %d out of range, using " - "default\n", val); + "3326 "LPFC_DRIVER_NAME"_fcp_cpu_map: %d out " + "of range, using default\n", val); phba->cfg_fcp_cpu_map = LPFC_HBA_CPU_MAP; return 0; } -static DEVICE_ATTR_RW(lpfc_fcp_cpu_map); +static DEVICE_ATTR(lpfc_fcp_cpu_map, S_IRUGO | S_IWUSR, + lpfc_fcp_cpu_map_show, lpfc_fcp_cpu_map_store); /* # lpfc_fcp_class: Determines FC class to use for the FCP protocol. @@ -5451,6 +5738,7 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1, LPFC_VPORT_ATTR_RW(first_burst_size, 0, 0, 65536, "First burst size for Targets that support first burst"); +#ifdef BUILD_NVME /* * lpfc_nvmet_fb_size: NVME Target mode supported first burst size. * When the driver is configured as an NVME target, this value is @@ -5473,6 +5761,7 @@ LPFC_ATTR_RW(nvmet_fb_size, 0, 0, 65536, */ LPFC_ATTR_RW(nvme_enable_fb, 0, 0, 1, "Enable First Burst feature for NVME Initiator."); +#endif /* # lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue @@ -5510,7 +5799,9 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) return 0; } lpfc_vport_param_store(max_scsicmpl_time); -static DEVICE_ATTR_RW(lpfc_max_scsicmpl_time); +static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR, + lpfc_max_scsicmpl_time_show, + lpfc_max_scsicmpl_time_store); /* # lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value @@ -5627,6 +5918,18 @@ LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality"); */ LPFC_ATTR_R(fdmi_on, 1, 0, 1, "Enable FDMI support"); +/* + * lpfc_enable_e2e: Enable E2E for ESM support + * 0 = disabled + * 1 = enabled (default) + * This will effect whether the driver registers a vendor specific + * E2EM port parameter with the Fabric Mgmt server. + * Value range is [0,1]. + */ +LPFC_ATTR_R(enable_e2e, 1, 0, 1, + "E2E: 1=enable 0=disable. Change only under direction of " + "Emulex Tech. Support"); + /* # Specifies the maximum number of ELS cmds we can have outstanding (for # discovery). Value range is [1,64]. Default value = 32. @@ -5682,6 +5985,7 @@ LPFC_ATTR_RW(task_mgmt_tmo, 60, 5, 180, LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " "MSI-X (2), if possible"); +#ifdef BUILD_NVME /* * lpfc_nvme_oas: Use the oas bit when sending NVME/NVMET IOs * @@ -5704,13 +6008,14 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1, */ LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2, "Embed NVME Command in WQE"); +#endif /* * lpfc_fcp_mq_threshold: Set the maximum number of Hardware Queues * the driver will advertise it supports to the SCSI layer. * * 0 = Set nr_hw_queues by the number of CPUs or HW queues. - * 1,128 = Manually specify the maximum nr_hw_queue value to be set, + * 1,256 = Manually specify the maximum nr_hw_queue value to be set, * * Value range is [0,256]. Default value is 8. */ @@ -5728,30 +6033,192 @@ LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF, * A hardware IO queue maps (qidx) to a specific driver CQ/WQ. * * 0 = Configure the number of hdw queues to the number of active CPUs. - * 1,128 = Manually specify how many hdw queues to use. + * 1,256 = Manually specify how many hdw queues to use. * - * Value range is [0,128]. Default value is 0. + * Value range is [0,256]. Default value is 0. */ LPFC_ATTR_R(hdw_queue, LPFC_HBA_HDWQ_DEF, LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX, "Set the number of I/O Hardware Queues"); +#if IS_ENABLED(CONFIG_X86) +/** + * lpfc_cpumask_irq_mode_init - initalizes cpumask of phba based on + * irq_chann_mode + * @phba: Pointer to HBA context object. + **/ +static void +lpfc_cpumask_irq_mode_init(struct lpfc_hba *phba) +{ + unsigned int cpu, first_cpu, numa_node = NUMA_NO_NODE; + const struct cpumask *sibling_mask; + struct cpumask *aff_mask = &phba->sli4_hba.irq_aff_mask; + + cpumask_clear(aff_mask); + + if (phba->irq_chann_mode == NUMA_MODE) { + /* Check if we're a NUMA architecture */ + numa_node = dev_to_node(&phba->pcidev->dev); + if (numa_node == NUMA_NO_NODE) { + phba->irq_chann_mode = NORMAL_MODE; + return; + } + } + + for_each_possible_cpu(cpu) { + switch (phba->irq_chann_mode) { + case NUMA_MODE: + if (cpu_to_node(cpu) == numa_node) + cpumask_set_cpu(cpu, aff_mask); + break; + case NHT_MODE: + sibling_mask = topology_sibling_cpumask(cpu); + first_cpu = cpumask_first(sibling_mask); + if (first_cpu < nr_cpu_ids) + cpumask_set_cpu(first_cpu, aff_mask); + break; + default: + break; + } + } +} +#endif + +static void +lpfc_assign_default_irq_chann(struct lpfc_hba *phba) +{ +#if IS_ENABLED(CONFIG_X86) + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* If AMD architecture, then default is NUMA_MODE */ + phba->irq_chann_mode = NUMA_MODE; + break; + case X86_VENDOR_INTEL: + /* If Intel architecture, then default is no hyperthread mode */ + phba->irq_chann_mode = NHT_MODE; + break; + default: + phba->irq_chann_mode = NORMAL_MODE; + break; + } + lpfc_cpumask_irq_mode_init(phba); +#else + phba->irq_chann_mode = NORMAL_MODE; +#endif +} + /* * lpfc_irq_chann: Set the number of IRQ vectors that are available * for Hardware Queues to utilize. This also will map to the number * of EQ / MSI-X vectors the driver will create. This should never be * more than the number of Hardware Queues * - * 0 = Configure number of IRQ Channels to the number of active CPUs. - * 1,128 = Manually specify how many IRQ Channels to use. + * 0 = Configure number of IRQ Channels to: + * if AMD architecture, number of CPUs on HBA's NUMA node + * if Intel architecture, number of physical CPUs. + * otherwise, number of active CPUs. + * [1,256] = Manually specify how many IRQ Channels to use. * - * Value range is [0,128]. Default value is 0. + * Value range is [0,256]. Default value is [0]. */ -LPFC_ATTR_R(irq_chann, - LPFC_HBA_HDWQ_DEF, - LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX, - "Set the number of I/O IRQ Channels"); +static uint lpfc_irq_chann = LPFC_IRQ_CHANN_DEF; +module_param(lpfc_irq_chann, uint, 0444); +MODULE_PARM_DESC(lpfc_irq_chann, "Set number of interrupt vectors to allocate"); + +/* lpfc_irq_chann_init - Set the hba irq_chann initial value + * @phba: lpfc_hba pointer. + * @val: contains the initial value + * + * Description: + * Validates the initial value is within range and assigns it to the + * adapter. If not in range, an error message is posted and the + * default value is assigned. + * + * Returns: + * zero if value is in range and is set + * -EINVAL if value was out of range + **/ +static int +lpfc_irq_chann_init(struct lpfc_hba *phba, uint32_t val) +{ + const struct cpumask *aff_mask; + + if (phba->cfg_use_msi != 2) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8532 use_msi = %u ignoring cfg_irq_numa\n", + phba->cfg_use_msi); + phba->irq_chann_mode = NORMAL_MODE; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; + return 0; + } + + /* Check if default setting was passed */ + if (val == LPFC_IRQ_CHANN_DEF) + lpfc_assign_default_irq_chann(phba); + + if (phba->irq_chann_mode != NORMAL_MODE) { + aff_mask = &phba->sli4_hba.irq_aff_mask; + + if (cpumask_empty(aff_mask)) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8533 Could not identify CPUS for " + "mode %d, ignoring\n", + phba->irq_chann_mode); + phba->irq_chann_mode = NORMAL_MODE; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; + } else { + phba->cfg_irq_chann = cpumask_weight(aff_mask); + + /* If no hyperthread mode, then set hdwq count to + * aff_mask weight as well + */ + if (phba->irq_chann_mode == NHT_MODE) + phba->cfg_hdw_queue = phba->cfg_irq_chann; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8543 lpfc_irq_chann set to %u " + "(mode: %d)\n", phba->cfg_irq_chann, + phba->irq_chann_mode); + } + } else { + if (val > LPFC_IRQ_CHANN_MAX) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8545 lpfc_irq_chann attribute cannot " + "be set to %u, allowed range is " + "[%u,%u]\n", + val, + LPFC_IRQ_CHANN_MIN, + LPFC_IRQ_CHANN_MAX); + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; + return -EINVAL; + } + phba->cfg_irq_chann = val; + } + + return 0; +} + +/** + * lpfc_irq_chann_show - Display value of irq_chann + * @dev: class converted to a Scsi_host structure. + * @attr: device attribute, not used. + * @buf: on return contains a string with the list sizes + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_irq_chann_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return scnprintf(buf, PAGE_SIZE, "%u\n", phba->cfg_irq_chann); +} + +static DEVICE_ATTR_RO(lpfc_irq_chann); /* # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. @@ -5785,6 +6252,30 @@ LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature."); */ LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); + +/* + * For T10 DIF / protection data support, the driver supports 4 modes + * of operation. + * + * Mode 1: (lpfc_enable_bg=1 lpfc_external_dif=1) + * All normal T10 DIF devices are supported. + * External DIF devices are supported. + * + * Mode 2: (lpfc_enable_bg=0 lpfc_external_dif=1) + * If you don't want to have the extra overhead of the upper SCSI Layer + * supporting T10-DIF, but you still want to support External DIF devices. + * Normal T10 DIF devices are NOT supported. + * External DIF devices are supported. + * + * Mode 3: (lpfc_enable_bg=1 lpfc_external_dif=0) + * All normal T10 DIF devices are supported. + * External DIF devices are NOT supported. + * + * Mode 4: (lpfc_enable_bg=0 lpfc_external_dif=1) + * No normal T10-DIF and no external DIF devices supported, + * This would be the driver default values for these module parameters. + */ + /* # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) # 0 = BlockGuard disabled (default) @@ -5793,11 +6284,21 @@ LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); */ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); +/* +# lpfc_external_dif: Enable External DIF support on select HBAs +# Only supported on SLI4 FC - if_type 2 HBAs +# 0 = External DIF disabled (default) +# 1 = External DIF enabled +# Value range is [0,1]. Default value is 0. +*/ +LPFC_ATTR_R(external_dif, 1, 0, 1, + "External T10-DIF Support, on select HBAs"); + /* # lpfc_prot_mask: i # - Bit mask of host protection capabilities used to register with the # SCSI mid-layer -# - Only meaningful if BG is turned on (lpfc_enable_bg=1). +# - Only meaningful if BG is turned on, lpfc_enable_bg = 1. # - Allows you to ultimately specify which profiles to use # - Default will result in registering capabilities for all profiles. # - SHOST_DIF_TYPE1_PROTECTION 1 @@ -5823,6 +6324,7 @@ LPFC_ATTR(prot_mask, # - Bit mask of protection guard types to register with the SCSI mid-layer # - Guard types are currently either 1) T10-DIF CRC 2) IP checksum # - Allows you to ultimately specify which profiles to use +# - Only meaningful if BG is turned on, lpfc_enable_bg = 1. # - Default will result in registering capabilities for all guard types # */ @@ -5887,7 +6389,7 @@ lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr, return len; } -static DEVICE_ATTR_RO(lpfc_sg_seg_cnt); +static DEVICE_ATTR(lpfc_sg_seg_cnt, S_IRUGO, lpfc_sg_seg_cnt_show, NULL); /** * lpfc_sg_seg_cnt_init - Set the hba sg_seg_cnt initial value @@ -5918,6 +6420,20 @@ lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val) return -EINVAL; } +#define THROTTLE_CNT_MIN 1 +#define THROTTLE_CNT_MAX 1000 +#define THROTTLE_CNT_DEF 10 +LPFC_ATTR_RW(throttle_log_cnt, THROTTLE_CNT_DEF, THROTTLE_CNT_MIN, + THROTTLE_CNT_MAX, "Do not exceed this number of messages " + "logged within throttle_log_time"); + +#define THROTTLE_TIME_MIN 1 +#define THROTTLE_TIME_MAX 60 +#define THROTTLE_TIME_DEF 1 +LPFC_ATTR_RW(throttle_log_time, THROTTLE_TIME_DEF, THROTTLE_TIME_MIN, + THROTTLE_TIME_MAX, "Do not exceed throttle_log_cnt within " + "this limit (seconds)"); + /* * lpfc_enable_mds_diags: Enable MDS Diagnostics * 0 = MDS Diagnostics disabled (default) @@ -5932,7 +6448,53 @@ LPFC_ATTR_RW(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); * [1-4] = Multiple of 1/4th Mb of host memory for FW logging * Value range [0..4]. Default value is 0 */ -LPFC_ATTR_RW(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging"); +LPFC_ATTR(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging"); +lpfc_param_show(ras_fwlog_buffsize); + +static ssize_t +lpfc_ras_fwlog_buffsize_set(struct lpfc_hba *phba, uint val) +{ + int ret = 0; + enum ras_state state; + + if (!lpfc_rangecheck(val, 0, 4)) + return -EINVAL; + + if (phba->cfg_ras_fwlog_buffsize == val) + return 0; + + if (phba->cfg_ras_fwlog_func != PCI_FUNC(phba->pcidev->devfn)) + return -EINVAL; + + spin_lock_irq(&phba->hbalock); + state = phba->ras_fwlog.state; + spin_unlock_irq(&phba->hbalock); + + if (state == REG_INPROGRESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "6147 RAS Logging " + "registration is in progress\n"); + return -EBUSY; + } + + /* For disable logging: stop the logs and free the DMA. + * For ras_fwlog_buffsize size change we still need to free and + * reallocate the DMA in lpfc_sli4_ras_fwlog_init. + */ + phba->cfg_ras_fwlog_buffsize = val; + if (state == ACTIVE) { + lpfc_ras_stop_fwlog(phba); + lpfc_sli4_ras_dma_free(phba); + } + + lpfc_sli4_ras_init(phba); + if (phba->ras_fwlog.ras_enabled) + ret = lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level, + LPFC_RAS_ENABLE_LOGGING); + return ret; +} + +lpfc_param_store(ras_fwlog_buffsize); +static DEVICE_ATTR_RW(lpfc_ras_fwlog_buffsize); /* * lpfc_ras_fwlog_level: Firmware logging verbosity level @@ -5959,16 +6521,362 @@ LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function"); */ LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery"); +/* Hidden module parameter */ +int lpfc_fabric_cgn_frequency = 100; /* 100 ms default */ +module_param(lpfc_fabric_cgn_frequency, int, 0444); +MODULE_PARM_DESC(lpfc_fabric_cgn_frequency, "Congestion signaling primitive freq"); + +/* Hidden module parameter */ +int lpfc_acqe_cgn_frequency = 10; /* 10 sec default */ +module_param(lpfc_acqe_cgn_frequency, int, 0444); +MODULE_PARM_DESC(lpfc_acqe_cgn_frequency, "Congestion signaling ACQE freq"); + +/* Hidden module parameter */ +int lpfc_use_cgn_signal = 1; /* 0 - only use FPINs, 1 - Use signals if avail */ +module_param(lpfc_use_cgn_signal, int, 0444); +MODULE_PARM_DESC(lpfc_use_cgn_signal, "Use Congestion signaling if available"); + +#ifndef BUILD_BRCMFCOE /* * lpfc_enable_dpp: Enable DPP on G7 * 0 = DPP on G7 disabled * 1 = DPP on G7 enabled (default) - * Value range is [0,1]. Default value is 1. + * Value range is [0,1]. Default value is 1 on X86, 0 on other architectures. */ +#ifdef CONFIG_X86 LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push"); +#else +LPFC_ATTR_RW(enable_dpp, 0, 0, 1, "Enable Direct Packet Push"); +#endif + +/* + * lpfc_enable_scsi_mq: Enable SCSI MQ support in lpfc + * 0 = disabled + * 1 = enabled (default) + * Value range is [0,1]. Default value is 1 + */ +LPFC_ATTR_R(enable_scsi_mq, 1, 0, 1, "Enable SCSI MQ support in LPFC"); + +/* + * lpfc_enable_auth: Enable DH-CHAP Authentication + * 0 = Authentication is disabled (default) + * 1 = Authentication is enabled + * Value range is [0,1]. Default value is 0. + */ +static uint lpfc_enable_auth = LPFC_AUTH_DISABLE; +module_param(lpfc_enable_auth, uint, S_IRUGO); +MODULE_PARM_DESC(lpfc_enable_auth, "Enable DH-CHAP Authentication"); +lpfc_param_show(enable_auth); +lpfc_param_init(enable_auth, LPFC_AUTH_DISABLE, LPFC_AUTH_DISABLE, + LPFC_AUTH_ENABLE); + +/** + * lpfc_enable_auth_store: Sets an attribute value. + * @phba: pointer the the adapter structure. + * @val: integer attribute value. + * + * Description: Sets the parameter to the new value. If the transition + * is to disable authentication, there is some cleanup done. + * + * Returns: + * zero on success + * -EINVAL if val is invalid + */ +static int +lpfc_enable_auth_set(struct lpfc_hba *phba, uint val) +{ + struct lpfc_vport *vport = phba->pport; + struct lpfc_nodelist *ndlp; + + if (!lpfc_rangecheck(val, LPFC_AUTH_DISABLE, LPFC_AUTH_ENABLE) || + phba->sli_rev < LPFC_SLI_REV4 || (phba->hba_flag & HBA_FCOE_MODE)) + return -EINVAL; + + if (val == phba->cfg_enable_auth) + return 0; + if (val == LPFC_AUTH_DISABLE) { + phba->cfg_enable_auth = val; + return 0; + } else if (val == LPFC_AUTH_ENABLE) { + phba->cfg_enable_auth = val; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; + + if (!phba->fc_fabparam.cmn.fcsp) + lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); + + return 0; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3033 lpfc_enable_auth attribute cannot be set to " + "%d, allowed range is [0, 1]\n", val); + return -EINVAL; +} + +lpfc_param_store(enable_auth); +static DEVICE_ATTR(lpfc_enable_auth, S_IRUGO | S_IWUSR, + lpfc_enable_auth_show, lpfc_enable_auth_store); + +static ssize_t +lpfc_authenticate_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + struct lpfc_name wwpn; + int status; + unsigned int cnt = count; + + if (!phba->cfg_enable_auth) + return -EACCES; + + if (lpfc_wwn_set(buf, cnt, wwpn.u.wwn)) + return -EINVAL; + + if (vport->port_state == LPFC_VPORT_FAILED) + return -ENXIO; + + if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || + (!phba->cfg_enable_auth)) + return -EPERM; + + if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN) + ndlp = lpfc_findnode_did(vport, Fabric_DID); + else + ndlp = lpfc_findnode_wwpn(vport, &wwpn); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return -EPERM; + + /* If vport already in the middle of authentication do not restart */ + if ((ndlp->dhc_cfg.msg == LPFC_AUTH_NEGOTIATE) || + (ndlp->dhc_cfg.msg == LPFC_DHCHAP_CHALLENGE) || + (ndlp->dhc_cfg.msg == LPFC_DHCHAP_REPLY)) + return -EAGAIN; + + status = lpfc_auth_start(vport, ndlp); + if (status) + return status; + return strlen(buf); +} +static DEVICE_ATTR(lpfc_authenticate, S_IWUSR, + NULL, lpfc_authenticate_store); + +static ssize_t +lpfc_auth_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_nodelist *ndlp; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + switch (ndlp->dhc_cfg.state) { + case LPFC_AUTH_UNKNOWN: + if (ndlp->dhc_cfg.msg == LPFC_AUTH_NEGOTIATE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_CHALLENGE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_REPLY || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_SUCCESS_REPLY) + return scnprintf(buf, PAGE_SIZE, "Authenticating\n"); + else + return scnprintf(buf, PAGE_SIZE, "Not Authenticated\n"); + case LPFC_AUTH_FAIL: + return scnprintf(buf, PAGE_SIZE, "Failed\n"); + case LPFC_AUTH_SUCCESS: + if (ndlp->dhc_cfg.msg == LPFC_AUTH_NEGOTIATE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_CHALLENGE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_REPLY || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_SUCCESS_REPLY) + return scnprintf(buf, PAGE_SIZE, "Authenticating\n"); + else if (ndlp->dhc_cfg.msg == LPFC_DHCHAP_SUCCESS) + return scnprintf(buf, PAGE_SIZE, "Authenticated\n"); + } + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_auth_dir_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + if (!phba->cfg_enable_auth || + ndlp->dhc_cfg.state != LPFC_AUTH_SUCCESS) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + if (ndlp->dhc_cfg.direction == AUTH_DIRECTION_LOCAL) + return scnprintf(buf, PAGE_SIZE, + "Local Authentication complete\n"); + else if (ndlp->dhc_cfg.direction == AUTH_DIRECTION_REMOTE) + return scnprintf(buf, PAGE_SIZE, + "Remote Authentication complete\n"); + else if (ndlp->dhc_cfg.direction == AUTH_DIRECTION_BIDI) + return scnprintf(buf, PAGE_SIZE, + "Bidirectional Authentication complete\n"); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_auth_protocol_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + if (phba->cfg_enable_auth && + ndlp->dhc_cfg.state == LPFC_AUTH_SUCCESS) + return scnprintf(buf, PAGE_SIZE, "1 (DH-CHAP)\n"); + else + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_auth_dhgroup_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + if (!phba->cfg_enable_auth || + ndlp->dhc_cfg.state != LPFC_AUTH_SUCCESS) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + switch (ndlp->dhc_cfg.dh_grp_id) { + case DH_GROUP_NULL: + return scnprintf(buf, PAGE_SIZE, "0 (NULL)\n"); + case DH_GROUP_1024: + return scnprintf(buf, PAGE_SIZE, "1 (1024)\n"); + case DH_GROUP_1280: + return scnprintf(buf, PAGE_SIZE, "2 (1280)\n"); + case DH_GROUP_1536: + return scnprintf(buf, PAGE_SIZE, "3 (1536)\n"); + case DH_GROUP_2048: + return scnprintf(buf, PAGE_SIZE, "4 (2048)\n"); + } + return scnprintf(buf, PAGE_SIZE, "%d (Unrecognized)\n", + ndlp->dhc_cfg.dh_grp_id); +} + +static ssize_t +lpfc_auth_hash_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + if (!phba->cfg_enable_auth || + ndlp->dhc_cfg.state != LPFC_AUTH_SUCCESS) + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); + + switch (ndlp->dhc_cfg.hash_id) { + case HASH_MD5: + return scnprintf(buf, PAGE_SIZE, "5 (MD5)\n"); + case HASH_SHA1: + return scnprintf(buf, PAGE_SIZE, "6 (SHA1)\n"); + } + return scnprintf(buf, PAGE_SIZE, "%d (Unrecognized)\n", + ndlp->dhc_cfg.hash_id); +} + +static ssize_t +lpfc_auth_last_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + unsigned long last_time; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "%d\n", -1); + + if (!phba->cfg_enable_auth || ndlp->dhc_cfg.last_auth == 0) + return scnprintf(buf, PAGE_SIZE, "%d\n", -1); + + last_time = jiffies_to_msecs((long)jiffies - + (long)ndlp->dhc_cfg.last_auth) / 1000; + return scnprintf(buf, PAGE_SIZE, "%ld\n", last_time); +} + +static ssize_t +lpfc_auth_next_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + unsigned long next_time; + + /* for now assume we're only authenticating the fabric */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return scnprintf(buf, PAGE_SIZE, "%d\n", -1); + + if (!phba->cfg_enable_auth || + ndlp->dhc_cfg.last_auth == 0 || + ndlp->dhc_cfg.reauth_interval == 0) + return scnprintf(buf, PAGE_SIZE, "%d\n", -1); + + next_time = ndlp->dhc_cfg.last_auth + + msecs_to_jiffies(ndlp->dhc_cfg.reauth_interval * 60000); + if (time_after(jiffies, next_time)) + return scnprintf(buf, PAGE_SIZE, "%d\n", -1); + + next_time = jiffies_to_msecs((long)next_time - (long)jiffies) / 1000; + return scnprintf(buf, PAGE_SIZE, "%ld\n", next_time); +} +static DEVICE_ATTR(auth_state, S_IRUGO, lpfc_auth_state_show, NULL); +static DEVICE_ATTR(auth_dir, S_IRUGO, lpfc_auth_dir_show, NULL); +static DEVICE_ATTR(auth_protocol, S_IRUGO, lpfc_auth_protocol_show, NULL); +static DEVICE_ATTR(auth_dhgroup, S_IRUGO, lpfc_auth_dhgroup_show, NULL); +static DEVICE_ATTR(auth_hash, S_IRUGO, lpfc_auth_hash_show, NULL); +static DEVICE_ATTR(auth_last, S_IRUGO, lpfc_auth_last_show, NULL); +static DEVICE_ATTR(auth_next, S_IRUGO, lpfc_auth_next_show, NULL); + +#endif struct device_attribute *lpfc_hba_attrs[] = { +#ifdef BUILD_NVME &dev_attr_nvme_info, +#endif &dev_attr_scsi_stat, &dev_attr_bg_info, &dev_attr_bg_guard_err, @@ -6014,10 +6922,14 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_multi_ring_rctl, &dev_attr_lpfc_multi_ring_type, &dev_attr_lpfc_fdmi_on, + &dev_attr_lpfc_enable_e2e, &dev_attr_lpfc_enable_SmartSAN, &dev_attr_lpfc_max_luns, &dev_attr_lpfc_enable_npiv, &dev_attr_lpfc_fcf_failover_policy, +#ifndef NO_APEX + &dev_attr_lpfc_enable_fcp_priority, +#endif &dev_attr_lpfc_enable_rrq, &dev_attr_nport_evt_cnt, &dev_attr_board_mode, @@ -6033,25 +6945,27 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_poll_tmo, &dev_attr_lpfc_task_mgmt_tmo, &dev_attr_lpfc_use_msi, +#ifdef BUILD_NVME &dev_attr_lpfc_nvme_oas, &dev_attr_lpfc_nvme_embed_cmd, +#endif &dev_attr_lpfc_fcp_imax, - &dev_attr_lpfc_force_rscn, &dev_attr_lpfc_cq_poll_threshold, &dev_attr_lpfc_cq_max_proc_limit, + &dev_attr_lpfc_force_rscn, &dev_attr_lpfc_fcp_cpu_map, &dev_attr_lpfc_fcp_mq_threshold, &dev_attr_lpfc_hdw_queue, &dev_attr_lpfc_irq_chann, &dev_attr_lpfc_suppress_rsp, +#ifdef BUILD_NVME &dev_attr_lpfc_nvmet_mrq, &dev_attr_lpfc_nvmet_mrq_post, &dev_attr_lpfc_nvme_enable_fb, &dev_attr_lpfc_nvmet_fb_size, +#endif &dev_attr_lpfc_enable_bg, - &dev_attr_lpfc_soft_wwnn, - &dev_attr_lpfc_soft_wwpn, - &dev_attr_lpfc_soft_wwn_enable, + &dev_attr_lpfc_external_dif, &dev_attr_lpfc_enable_hba_reset, &dev_attr_lpfc_enable_hba_heartbeat, &dev_attr_lpfc_EnableXLane, @@ -6070,22 +6984,36 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_sriov_nr_virtfn, &dev_attr_lpfc_req_fw_upgrade, &dev_attr_lpfc_suppress_link_up, - &dev_attr_lpfc_iocb_cnt, &dev_attr_iocb_hw, + &dev_attr_pls, + &dev_attr_pt, &dev_attr_txq_hw, &dev_attr_txcmplq_hw, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, - &dev_attr_lpfc_dss, &dev_attr_lpfc_sriov_hw_max_virtfn, &dev_attr_protocol, &dev_attr_lpfc_xlane_supported, + &dev_attr_lpfc_throttle_log_cnt, + &dev_attr_lpfc_throttle_log_time, &dev_attr_lpfc_enable_mds_diags, &dev_attr_lpfc_ras_fwlog_buffsize, &dev_attr_lpfc_ras_fwlog_level, &dev_attr_lpfc_ras_fwlog_func, &dev_attr_lpfc_enable_bbcr, +#ifndef BUILD_BRCMFCOE &dev_attr_lpfc_enable_dpp, + &dev_attr_lpfc_enable_scsi_mq, + &dev_attr_lpfc_enable_auth, + &dev_attr_lpfc_authenticate, + + &dev_attr_auth_state, + &dev_attr_auth_dir, + &dev_attr_auth_protocol, + &dev_attr_auth_dhgroup, + &dev_attr_auth_hash, + &dev_attr_auth_last, + &dev_attr_auth_next, +#endif + &dev_attr_cmf_info, NULL, }; @@ -6112,8 +7040,7 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, &dev_attr_lpfc_static_vport, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, + &dev_attr_cmf_info, NULL, }; @@ -6509,11 +7436,17 @@ lpfc_get_host_speed(struct Scsi_Host *shost) fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; } - } else if (lpfc_is_link_up(phba) && (phba->hba_flag & HBA_FCOE_MODE)) { + } else if ((lpfc_is_link_up(phba)) && (phba->hba_flag & HBA_FCOE_MODE)) { switch (phba->fc_linkspeed) { + case LPFC_ASYNC_LINK_SPEED_1GBPS: + fc_host_speed(shost) = FC_PORTSPEED_1GBIT; + break; case LPFC_ASYNC_LINK_SPEED_10GBPS: fc_host_speed(shost) = FC_PORTSPEED_10GBIT; break; + case LPFC_ASYNC_LINK_SPEED_20GBPS: + fc_host_speed(shost) = FC_PORTSPEED_20GBIT; + break; case LPFC_ASYNC_LINK_SPEED_25GBPS: fc_host_speed(shost) = FC_PORTSPEED_25GBIT; break; @@ -6582,6 +7515,7 @@ lpfc_get_stats(struct Scsi_Host *shost) struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; + unsigned long seconds; int rc = 0; /* @@ -6607,19 +7541,15 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) { + if (vport->fc_flag & FC_OFFLINE_MODE) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } - } else { + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } + + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return NULL; } memset(hs, 0, sizeof (struct fc_host_statistics)); @@ -6643,19 +7573,15 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) { + if (vport->fc_flag & FC_OFFLINE_MODE) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } - } else { + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } + + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return NULL; } hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; @@ -6690,7 +7616,12 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->dumped_frames = -1; - hs->seconds_since_last_reset = ktime_get_seconds() - psli->stats_start; + seconds = get_seconds(); + if (seconds < psli->stats_start) + hs->seconds_since_last_reset = seconds + + ((unsigned long)-1 - psli->stats_start); + else + hs->seconds_since_last_reset = seconds - psli->stats_start; mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6728,19 +7659,15 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } - } else { + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } + + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return; } memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); @@ -6750,19 +7677,15 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } - } else { + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } + + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free( pmboxq, phba->mbox_mem_pool); + return; } lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; @@ -6777,7 +7700,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) else lso->link_events = (phba->fc_eventTag >> 1); - psli->stats_start = ktime_get_seconds(); + psli->stats_start = get_seconds(); mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6872,9 +7795,9 @@ lpfc_get_starget_port_name(struct scsi_target *starget) static void lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { +#if (IS_ENABLED(CONFIG_NVME_FC)) && defined(BUILD_NVME) struct lpfc_rport_data *rdata = rport->dd_data; struct lpfc_nodelist *ndlp = rdata->pnode; -#if (IS_ENABLED(CONFIG_NVME_FC)) struct lpfc_nvme_rport *nrport = NULL; #endif @@ -6883,6 +7806,7 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) else rport->dev_loss_tmo = 1; +#if (IS_ENABLED(CONFIG_NVME_FC)) && defined(BUILD_NVME) if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { dev_info(&rport->dev, "Cannot find remote node to " "set rport dev loss tmo, port_id x%x\n", @@ -6890,7 +7814,6 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) return; } -#if (IS_ENABLED(CONFIG_NVME_FC)) nrport = lpfc_ndlp_get_nrport(ndlp); if (nrport && nrport->remoteport) @@ -7114,6 +8037,9 @@ lpfc_get_hba_function_mode(struct lpfc_hba *phba) void lpfc_get_cfgparam(struct lpfc_hba *phba) { + uint32_t if_type; + + lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched); lpfc_ns_query_init(phba, lpfc_ns_query); lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset); @@ -7131,22 +8057,26 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy); lpfc_enable_rrq_init(phba, lpfc_enable_rrq); +#ifndef NO_APEX + lpfc_enable_fcp_priority_init(phba, lpfc_enable_fcp_priority); +#endif lpfc_fdmi_on_init(phba, lpfc_fdmi_on); + lpfc_enable_e2e_init(phba, lpfc_enable_e2e); lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN); lpfc_use_msi_init(phba, lpfc_use_msi); +#ifdef BUILD_NVME lpfc_nvme_oas_init(phba, lpfc_nvme_oas); lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd); +#endif lpfc_fcp_imax_init(phba, lpfc_fcp_imax); - lpfc_force_rscn_init(phba, lpfc_force_rscn); lpfc_cq_poll_threshold_init(phba, lpfc_cq_poll_threshold); lpfc_cq_max_proc_limit_init(phba, lpfc_cq_max_proc_limit); + lpfc_force_rscn_init(phba, lpfc_force_rscn); lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map); lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_EnableXLane_init(phba, lpfc_EnableXLane); - if (phba->sli_rev != LPFC_SLI_REV4) - phba->cfg_EnableXLane = 0; lpfc_XLanePriority_init(phba, lpfc_XLanePriority); memset(phba->cfg_oas_tgt_wwpn, 0, (8 * sizeof(uint8_t))); @@ -7158,38 +8088,60 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_bg_init(phba, lpfc_enable_bg); lpfc_prot_mask_init(phba, lpfc_prot_mask); lpfc_prot_guard_init(phba, lpfc_prot_guard); - if (phba->sli_rev == LPFC_SLI_REV4) - phba->cfg_poll = 0; - else + lpfc_external_dif_init(phba, lpfc_external_dif); + + if (phba->sli_rev != LPFC_SLI_REV4) { + phba->cfg_EnableXLane = 0; + phba->cfg_external_dif = 0; + phba->cfg_enable_e2e = 0; phba->cfg_poll = lpfc_poll; + } else { + /* Only supported on SLI4 FC - if_type 2/6 */ + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type < LPFC_SLI_INTF_IF_TYPE_2) + phba->cfg_external_dif = 0; + phba->cfg_poll = 0; + } +#if defined(BUILD_CITRIX_XS) + phba->cfg_enable_bg = 0; +#endif /* Get the function mode */ lpfc_get_hba_function_mode(phba); /* BlockGuard allowed for FC only. */ - if (phba->cfg_enable_bg && phba->hba_flag & HBA_FCOE_MODE) { + if ((phba->cfg_enable_bg || phba->cfg_external_dif) && + phba->hba_flag & HBA_FCOE_MODE) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0581 BlockGuard feature not supported\n"); /* If set, clear the BlockGuard support param */ phba->cfg_enable_bg = 0; - } else if (phba->cfg_enable_bg) { + } else if (phba->cfg_enable_bg || phba->cfg_external_dif) phba->sli3_options |= LPFC_SLI3_BG_ENABLED; - } - lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp); lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type); +#ifdef BUILD_NVME lpfc_nvmet_mrq_init(phba, lpfc_nvmet_mrq); lpfc_nvmet_mrq_post_init(phba, lpfc_nvmet_mrq_post); /* Initialize first burst. Target vs Initiator are different. */ lpfc_nvme_enable_fb_init(phba, lpfc_nvme_enable_fb); lpfc_nvmet_fb_size_init(phba, lpfc_nvmet_fb_size); +#endif lpfc_fcp_mq_threshold_init(phba, lpfc_fcp_mq_threshold); lpfc_hdw_queue_init(phba, lpfc_hdw_queue); lpfc_irq_chann_init(phba, lpfc_irq_chann); lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr); +#ifndef BUILD_BRCMFCOE lpfc_enable_dpp_init(phba, lpfc_enable_dpp); + lpfc_enable_scsi_mq_init(phba, lpfc_enable_scsi_mq); + lpfc_enable_auth_init(phba, lpfc_enable_auth); +#endif + + phba->cgn_p.cgn_param_mode = LPFC_CFG_OFF; + phba->cmf_active_mode = LPFC_CFG_OFF; if (phba->sli_rev != LPFC_SLI_REV4) { /* NVME only supported on SLI4 */ @@ -7198,6 +8150,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; phba->cfg_enable_bbcr = 0; phba->cfg_xri_rebalancing = 0; +#ifndef BUILD_BRCMFCOE + phba->cfg_enable_auth = LPFC_AUTH_DISABLE; +#endif } else { /* We MUST have FCP support */ if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) @@ -7205,10 +8160,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) } phba->cfg_auto_imax = (phba->cfg_fcp_imax) ? 0 : 1; - phba->cfg_enable_pbde = 0; /* A value of 0 means use the number of CPUs found in the system */ + if (phba->cfg_fcp_mq_threshold == 0) + phba->cfg_fcp_mq_threshold = phba->sli4_hba.num_present_cpu; if (phba->cfg_hdw_queue == 0) phba->cfg_hdw_queue = phba->sli4_hba.num_present_cpu; if (phba->cfg_irq_chann == 0) @@ -7216,19 +8172,18 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) if (phba->cfg_irq_chann > phba->cfg_hdw_queue) phba->cfg_irq_chann = phba->cfg_hdw_queue; - phba->cfg_soft_wwnn = 0L; - phba->cfg_soft_wwpn = 0L; +#ifdef BUILD_NVME +#endif lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); - lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_aer_support_init(phba, lpfc_aer_support); lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade); lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); - lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); lpfc_delay_discovery_init(phba, lpfc_delay_discovery); lpfc_sli_mode_init(phba, lpfc_sli_mode); - phba->cfg_enable_dss = 1; + lpfc_throttle_log_cnt_init(phba, lpfc_throttle_log_cnt); + lpfc_throttle_log_time_init(phba, lpfc_throttle_log_time); lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize); lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level); @@ -7245,12 +8200,26 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) { - if (phba->cfg_hdw_queue > phba->sli4_hba.num_present_cpu) + int logit = 0; + + if (phba->cfg_hdw_queue > phba->sli4_hba.num_present_cpu) { phba->cfg_hdw_queue = phba->sli4_hba.num_present_cpu; - if (phba->cfg_irq_chann > phba->sli4_hba.num_present_cpu) + logit = 1; + } + if (phba->cfg_irq_chann > phba->sli4_hba.num_present_cpu) { phba->cfg_irq_chann = phba->sli4_hba.num_present_cpu; - if (phba->cfg_irq_chann > phba->cfg_hdw_queue) + logit = 1; + } + if (phba->cfg_irq_chann > phba->cfg_hdw_queue) { phba->cfg_irq_chann = phba->cfg_hdw_queue; + logit = 1; + } + if (logit) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2006 Reducing Queues - CPU limitation: " + "IRQ %d HDWQ %d\n", + phba->cfg_irq_chann, + phba->cfg_hdw_queue); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME && phba->nvmet_support) { @@ -7271,11 +8240,11 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) } if (!phba->cfg_nvmet_mrq) - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; /* Adjust lpfc_nvmet_mrq to avoid running out of WQE slots */ - if (phba->cfg_nvmet_mrq > phba->cfg_irq_chann) { - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + if (phba->cfg_nvmet_mrq > phba->cfg_hdw_queue) { + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, "6018 Adjust lpfc_nvmet_mrq to %d\n", phba->cfg_nvmet_mrq); diff --git a/drivers/scsi/lpfc/lpfc_attr.h b/drivers/scsi/lpfc/lpfc_attr.h index 9659a8fff..a19c6312f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.h +++ b/drivers/scsi/lpfc/lpfc_attr.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -21,6 +21,8 @@ * included with this package. * *******************************************************************/ +#ifndef BUILD_BRCMFCOE + #define LPFC_ATTR(name, defval, minval, maxval, desc) \ static uint lpfc_##name = defval;\ module_param(lpfc_##name, uint, S_IRUGO);\ @@ -126,3 +128,251 @@ lpfc_vport_param_set(name, defval, minval, maxval)\ lpfc_vport_param_store(name)\ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ lpfc_##name##_show, lpfc_##name##_store) + +#else + +#define LPFC_ATTR(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_init(name, defval, minval, maxval) + +#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_BBCR_ATTR_RW(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_init(name, defval, minval, maxval) + +#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ULL_ATTR_R(name, defval, minval, maxval, desc) \ +static uint64_t brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, ullong, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +lpfc_vport_param_set(name, defval, minval, maxval)\ +lpfc_vport_param_store(name)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_hex_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ +static uint brcmfcoe_##name = defval;\ +module_param(brcmfcoe_##name, uint, S_IRUGO);\ +MODULE_PARM_DESC(brcmfcoe_##name, desc);\ +lpfc_vport_param_hex_show(name)\ +lpfc_vport_param_init(name, defval, minval, maxval)\ +lpfc_vport_param_set(name, defval, minval, maxval)\ +lpfc_vport_param_store(name)\ +static DEVICE_ATTR(brcmfcoe_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define lpfc_drvr_version brcmfcoe_drvr_version +#define lpfc_enable_fip brcmfcoe_enable_fip +#define lpfc_temp_sensor brcmfcoe_temp_sensor +#define lpfc_sriov_hw_max_virtfn brcmfcoe_sriov_hw_max_virtfn +#define lpfc_xlane_supported brcmfcoe_xlane_supported + +#define dev_attr_lpfc_log_verbose dev_attr_brcmfcoe_log_verbose +#define dev_attr_lpfc_lun_queue_depth dev_attr_brcmfcoe_lun_queue_depth +#define dev_attr_lpfc_tgt_queue_depth dev_attr_brcmfcoe_tgt_queue_depth +#define dev_attr_lpfc_hba_queue_depth dev_attr_brcmfcoe_hba_queue_depth +#define dev_attr_lpfc_peer_port_login dev_attr_brcmfcoe_peer_port_login +#define dev_attr_lpfc_fcp_class dev_attr_brcmfcoe_fcp_class +#define dev_attr_lpfc_use_adisc dev_attr_brcmfcoe_use_adisc +#define dev_attr_lpfc_first_burst_size dev_attr_brcmfcoe_first_burst_size +#define dev_attr_lpfc_ack0 dev_attr_brcmfcoe_ack0 +#define dev_attr_lpfc_xri_rebalancing dev_attr_brcmfcoe_xri_rebalancing +#define dev_attr_lpfc_scan_down dev_attr_brcmfcoe_scan_down +#define dev_attr_lpfc_fcp_io_sched dev_attr_brcmfcoe_fcp_io_sched +#define dev_attr_lpfc_ns_query dev_attr_brcmfcoe_ns_query +#define dev_attr_lpfc_fcp2_no_tgt_reset dev_attr_brcmfcoe_fcp2_no_tgt_reset +#define dev_attr_lpfc_cr_delay dev_attr_brcmfcoe_cr_delay +#define dev_attr_lpfc_cr_count dev_attr_brcmfcoe_cr_count +#define dev_attr_lpfc_multi_ring_support dev_attr_brcmfcoe_multi_ring_support +#define dev_attr_lpfc_multi_ring_rctl dev_attr_brcmfcoe_multi_ring_rctl +#define dev_attr_lpfc_multi_ring_type dev_attr_brcmfcoe_multi_ring_type +#define dev_attr_lpfc_fdmi_on dev_attr_brcmfcoe_fdmi_on +#define dev_attr_lpfc_enable_SmartSAN dev_attr_brcmfcoe_enable_SmartSAN +#define dev_attr_lpfc_max_luns dev_attr_brcmfcoe_max_luns +#define dev_attr_lpfc_fcf_failover_policy dev_attr_brcmfcoe_fcf_failover_policy +#define dev_attr_lpfc_enable_fcp_priority dev_attr_brcmfcoe_enable_fcp_priority +#define dev_attr_lpfc_poll_tmo dev_attr_brcmfcoe_poll_tmo +#define dev_attr_lpfc_task_mgmt_tmo dev_attr_brcmfcoe_task_mgmt_tmo +#define dev_attr_lpfc_enable_npiv dev_attr_brcmfcoe_enable_npiv +#define dev_attr_lpfc_use_msi dev_attr_brcmfcoe_use_msi +#define dev_attr_lpfc_cq_max_proc_limit dev_attr_brcmfcoe_cq_max_proc_limit +#define dev_attr_lpfc_fcp_imax dev_attr_brcmfcoe_fcp_imax +#define dev_attr_lpfc_cq_poll_threshold dev_attr_brcmfcoe_cq_poll_threshold +#define dev_attr_lpfc_fcp_mq_threshold dev_attr_brcmfcoe_fcp_mq_threshold +#define dev_attr_lpfc_hdw_queue dev_attr_brcmfcoe_hdw_queue +#define dev_attr_lpfc_irq_chann dev_attr_brcmfcoe_irq_chann +#define dev_attr_lpfc_enable_bg dev_attr_brcmfcoe_enable_bg +#define dev_attr_lpfc_external_dif dev_attr_brcmfcoe_external_dif +#define dev_attr_lpfc_enable_hba_reset dev_attr_brcmfcoe_enable_hba_reset +#define dev_attr_lpfc_enable_hba_heartbeat \ + dev_attr_brcmfcoe_enable_hba_heartbeat +#define dev_attr_lpfc_EnableXLane dev_attr_brcmfcoe_EnableXLane +#define dev_attr_lpfc_XLanePriority dev_attr_brcmfcoe_XLanePriority +#define dev_attr_lpfc_sg_seg_cnt dev_attr_brcmfcoe_sg_seg_cnt +#define dev_attr_lpfc_enable_rrq dev_attr_brcmfcoe_enable_rrq +#define dev_attr_lpfc_suppress_link_up dev_attr_brcmfcoe_suppress_link_up +#define dev_attr_lpfc_throttle_log_cnt dev_attr_brcmfcoe_throttle_log_cnt +#define dev_attr_lpfc_throttle_log_time dev_attr_brcmfcoe_throttle_log_time +#define dev_attr_lpfc_enable_mds_diags dev_attr_brcmfcoe_enable_mds_diags +#define lpfc_enable_bbcr brcmfcoe_enable_bbcr +#define dev_attr_lpfc_enable_da_id dev_attr_brcmfcoe_enable_da_id +#define dev_attr_lpfc_suppress_rsp dev_attr_brcmfcoe_suppress_rsp +#define dev_attr_lpfc_enable_fc4_type dev_attr_brcmfcoe_enable_fc4_type +#define dev_attr_lpfc_xri_split dev_attr_brcmfcoe_xri_split +#define dev_attr_lpfc_ras_fwlog_buffsize dev_attr_brcmfcoe_ras_fwlog_buffsize +#define dev_attr_lpfc_ras_fwlog_level dev_attr_brcmfcoe_ras_fwlog_level +#define dev_attr_lpfc_ras_fwlog_func dev_attr_brcmfcoe_ras_fwlog_func + +#define lpfc_fcp_io_sched brcmfcoe_fcp_io_sched +#define lpfc_ns_query brcmfcoe_ns_query +#define lpfc_fcp2_no_tgt_reset brcmfcoe_fcp2_no_tgt_reset +#define lpfc_cr_delay brcmfcoe_cr_delay +#define lpfc_cr_count brcmfcoe_cr_count +#define lpfc_multi_ring_support brcmfcoe_multi_ring_support +#define lpfc_multi_ring_rctl brcmfcoe_multi_ring_rctl +#define lpfc_multi_ring_type brcmfcoe_multi_ring_type +#define lpfc_ack0 brcmfcoe_ack0 +#define lpfc_xri_rebalancing brcmfcoe_xri_rebalancing +#define lpfc_topology brcmfcoe_topology +#define lpfc_link_speed brcmfcoe_link_speed +#define lpfc_poll_tmo brcmfcoe_poll_tmo +#define lpfc_task_mgmt_tmo brcmfcoe_task_mgmt_tmo +#define lpfc_enable_npiv brcmfcoe_enable_npiv +#define lpfc_fcf_failover_policy brcmfcoe_fcf_failover_policy +#define lpfc_enable_rrq brcmfcoe_enable_rrq +#define lpfc_enable_fcp_priority brcmfcoe_enable_fcp_priority +#define lpfc_fdmi_on brcmfcoe_fdmi_on +#define lpfc_enable_SmartSAN brcmfcoe_enable_SmartSAN +#define lpfc_use_msi brcmfcoe_use_msi +#define lpfc_cq_max_proc_limit brcmfcoe_cq_max_proc_limit +#define lpfc_fcp_imax brcmfcoe_fcp_imax +#define lpfc_cq_poll_threshold brcmfcoe_cq_poll_threshold +#define lpfc_fcp_cpu_map brcmfcoe_fcp_cpu_map +#define lpfc_fcp_mq_threshold brcmfcoe_fcp_mq_threshold +#define lpfc_hdw_queue brcmfcoe_hdw_queue +#define lpfc_irq_chann brcmfcoe_irq_chann +#define lpfc_enable_hba_reset brcmfcoe_enable_hba_reset +#define lpfc_enable_hba_heartbeat brcmfcoe_enable_hba_heartbeat +#define lpfc_EnableXLane brcmfcoe_EnableXLane +#define lpfc_XLanePriority brcmfcoe_XLanePriority +#define lpfc_enable_bg brcmfcoe_enable_bg +#define lpfc_prot_mask brcmfcoe_prot_mask +#define lpfc_prot_guard brcmfcoe_prot_guard +#define lpfc_external_dif brcmfcoe_external_dif +#define lpfc_sg_seg_cnt brcmfcoe_sg_seg_cnt +#define lpfc_hba_queue_depth brcmfcoe_hba_queue_depth +#define lpfc_log_verbose brcmfcoe_log_verbose +#define lpfc_aer_support brcmfcoe_aer_support +#define lpfc_sriov_nr_virtfn brcmfcoe_sriov_nr_virtfn +#define lpfc_req_fw_upgrade brcmfcoe_req_fw_upgrade +#define lpfc_suppress_link_up brcmfcoe_suppress_link_up +#define lpfc_throttle_log_cnt brcmfcoe_throttle_log_cnt +#define lpfc_throttle_log_time brcmfcoe_throttle_log_time +#define lpfc_enable_mds_diags brcmfcoe_enable_mds_diags +#define lpfc_lun_queue_depth brcmfcoe_lun_queue_depth +#define lpfc_tgt_queue_depth brcmfcoe_tgt_queue_depth +#define lpfc_peer_port_login brcmfcoe_peer_port_login +#define lpfc_fcp_class brcmfcoe_fcp_class +#define lpfc_use_adisc brcmfcoe_use_adisc +#define lpfc_first_burst_size brcmfcoe_first_burst_size +#define lpfc_discovery_threads brcmfcoe_discovery_threads +#define lpfc_max_luns brcmfcoe_max_luns +#define lpfc_scan_down brcmfcoe_scan_down +#define lpfc_enable_da_id brcmfcoe_enable_da_id +#define lpfc_sli_mode brcmfcoe_sli_mode +#define lpfc_delay_discovery brcmfcoe_delay_discovery +#define lpfc_devloss_tmo brcmfcoe_devloss_tmo +#define lpfc_drvr_stat_data brcmfcoe_drvr_stat_data +#define lpfc_max_scsicmpl_time brcmfcoe_max_scsicmpl_time +#define lpfc_nodev_tmo brcmfcoe_nodev_tmo +#define lpfc_poll brcmfcoe_poll +#define lpfc_stat_data_ctrl brcmfcoe_stat_data_ctrl +#define lpfc_xlane_lun brcmfcoe_xlane_lun +#define lpfc_xlane_lun_state brcmfcoe_xlane_lun_state +#define lpfc_xlane_lun_status brcmfcoe_xlane_lun_status +#define lpfc_xlane_priority brcmfcoe_xlane_priority +#define lpfc_xlane_tgt brcmfcoe_xlane_tgt +#define lpfc_xlane_vpt brcmfcoe_xlane_vpt +#define lpfc_enable_fc4_type brcmfcoe_enable_fc4_type +#define lpfc_xri_split brcmfcoe_xri_split +#define lpfc_suppress_rsp brcmfcoe_suppress_rsp +#define lpfc_ras_fwlog_buffsize brcmfcoe_ras_fwlog_buffsize +#define lpfc_ras_fwlog_level brcmfcoe_ras_fwlog_level +#define lpfc_ras_fwlog_func brcmfcoe_ras_fwlog_func +#endif diff --git a/drivers/scsi/lpfc/lpfc_auth.c b/drivers/scsi/lpfc/lpfc_auth.c new file mode 100644 index 000000000..c66fe750c --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_auth.c @@ -0,0 +1,2296 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2018-2020 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.broadcom.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ +/* See Fibre Channel protocol T11 FC-SP-2 for details */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "lpfc_hw4.h" +#include "lpfc_hw.h" +#include "lpfc_sli.h" +#include "lpfc_sli4.h" +#include "lpfc_nl.h" +#include "lpfc_disc.h" +#include "lpfc_scsi.h" +#include "lpfc.h" +#include "lpfc_logmsg.h" +#include "lpfc_crtn.h" +#include "lpfc_vport.h" +#include "lpfc_debugfs.h" +#include "lpfc_auth.h" + +struct dh_group dh_group_array[5] = { + { + DH_GROUP_NULL, 0, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } + }, + { + DH_GROUP_1024, 128, + { + 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, + 0x9C, 0x33, 0xF8, 0x0A, 0xFA, 0x8F, 0xC5, 0xE8, + 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, 0x3C, 0x0B, + 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, + 0xD6, 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, + 0x38, 0x3B, 0x48, 0x13, 0xD6, 0x92, 0xC6, 0xE0, + 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, 0xE4, + 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, + 0x5D, 0xC7, 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, + 0xCE, 0x8E, 0xF4, 0xAD, 0x69, 0xB1, 0x5D, 0x49, + 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, + 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, + 0x68, 0xED, 0xBC, 0x3C, 0x05, 0x72, 0x6C, 0xC0, + 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, 0xAA, 0x9A, + 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, + 0x9F, 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } + }, + { + DH_GROUP_1280, 160, + { + 0xD7, 0x79, 0x46, 0x82, 0x6E, 0x81, 0x19, 0x14, + 0xB3, 0x94, 0x01, 0xD5, 0x6A, 0x0A, 0x78, 0x43, + 0xA8, 0xE7, 0x57, 0x5D, 0x73, 0x8C, 0x67, 0x2A, + 0x09, 0x0A, 0xB1, 0x18, 0x7D, 0x69, 0x0D, 0xC4, + 0x38, 0x72, 0xFC, 0x06, 0xA7, 0xB6, 0xA4, 0x3F, + 0x3B, 0x95, 0xBE, 0xAE, 0xC7, 0xDF, 0x04, 0xB9, + 0xD2, 0x42, 0xEB, 0xDC, 0x48, 0x11, 0x11, 0x28, + 0x32, 0x16, 0xCE, 0x81, 0x6E, 0x00, 0x4B, 0x78, + 0x6C, 0x5F, 0xCE, 0x85, 0x67, 0x80, 0xD4, 0x18, + 0x37, 0xD9, 0x5A, 0xD7, 0x87, 0xA5, 0x0B, 0xBE, + 0x90, 0xBD, 0x3A, 0x9C, 0x98, 0xAC, 0x0F, 0x5F, + 0xC0, 0xDE, 0x74, 0x4B, 0x1C, 0xDE, 0x18, 0x91, + 0x69, 0x08, 0x94, 0xBC, 0x1F, 0x65, 0xE0, 0x0D, + 0xE1, 0x5B, 0x4B, 0x2A, 0xA6, 0xD8, 0x71, 0x00, + 0xC9, 0xEC, 0xC2, 0x52, 0x7E, 0x45, 0xEB, 0x84, + 0x9D, 0xEB, 0x14, 0xBB, 0x20, 0x49, 0xB1, 0x63, + 0xEA, 0x04, 0x18, 0x7F, 0xD2, 0x7C, 0x1B, 0xD9, + 0xC7, 0x95, 0x8C, 0xD4, 0x0C, 0xE7, 0x06, 0x7A, + 0x9C, 0x02, 0x4F, 0x9B, 0x7C, 0x5A, 0x0B, 0x4F, + 0x50, 0x03, 0x68, 0x61, 0x61, 0xF0, 0x60, 0x5B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } + }, + { + DH_GROUP_1536, 192, + { + 0x9D, 0xEF, 0x3C, 0xAF, 0xB9, 0x39, 0x27, 0x7A, + 0xB1, 0xF1, 0x2A, 0x86, 0x17, 0xA4, 0x7B, 0xBB, + 0xDB, 0xA5, 0x1D, 0xF4, 0x99, 0xAC, 0x4C, 0x80, + 0xBE, 0xEE, 0xA9, 0x61, 0x4B, 0x19, 0xCC, 0x4D, + 0x5F, 0x4F, 0x5F, 0x55, 0x6E, 0x27, 0xCB, 0xDE, + 0x51, 0xC6, 0xA9, 0x4B, 0xE4, 0x60, 0x7A, 0x29, + 0x15, 0x58, 0x90, 0x3B, 0xA0, 0xD0, 0xF8, 0x43, + 0x80, 0xB6, 0x55, 0xBB, 0x9A, 0x22, 0xE8, 0xDC, + 0xDF, 0x02, 0x8A, 0x7C, 0xEC, 0x67, 0xF0, 0xD0, + 0x81, 0x34, 0xB1, 0xC8, 0xB9, 0x79, 0x89, 0x14, + 0x9B, 0x60, 0x9E, 0x0B, 0xE3, 0xBA, 0xB6, 0x3D, + 0x47, 0x54, 0x83, 0x81, 0xDB, 0xC5, 0xB1, 0xFC, + 0x76, 0x4E, 0x3F, 0x4B, 0x53, 0xDD, 0x9D, 0xA1, + 0x15, 0x8B, 0xFD, 0x3E, 0x2B, 0x9C, 0x8C, 0xF5, + 0x6E, 0xDF, 0x01, 0x95, 0x39, 0x34, 0x96, 0x27, + 0xDB, 0x2F, 0xD5, 0x3D, 0x24, 0xB7, 0xC4, 0x86, + 0x65, 0x77, 0x2E, 0x43, 0x7D, 0x6C, 0x7F, 0x8C, + 0xE4, 0x42, 0x73, 0x4A, 0xF7, 0xCC, 0xB7, 0xAE, + 0x83, 0x7C, 0x26, 0x4A, 0xE3, 0xA9, 0xBE, 0xB8, + 0x7F, 0x8A, 0x2F, 0xE9, 0xB8, 0xB5, 0x29, 0x2E, + 0x5A, 0x02, 0x1F, 0xFF, 0x5E, 0x91, 0x47, 0x9E, + 0x8C, 0xE7, 0xA2, 0x8C, 0x24, 0x42, 0xC6, 0xF3, + 0x15, 0x18, 0x0F, 0x93, 0x49, 0x9A, 0x23, 0x4D, + 0xCF, 0x76, 0xE3, 0xFE, 0xD1, 0x35, 0xF9, 0xBB, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } + }, + { + DH_GROUP_2048, 256, + { + 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, + 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, + 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, + 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, + 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, + 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, + 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, + 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, + 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, + 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, + 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, + 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, + 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, + 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, + 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, + 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, + 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, + 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, + 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, + 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, + 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, + 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, + 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, + 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, + 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, + 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, + 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, + 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, + 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, + 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, + 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, + 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73, + } + }, +}; + +/** + * lpfc_auth_cancel_tmr + * @ptr: pointer to a node-list data structure. + * + * This routine cancels any pending authentication timer. + * + **/ +void +lpfc_auth_cancel_tmr(struct lpfc_nodelist *ndlp) +{ + struct lpfc_vport *vport = ndlp->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (!(ndlp->nlp_flag & NLP_AUTH_TMO)) + return; + + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_AUTH_TMO; + spin_unlock_irq(shost->host_lock); + del_timer_sync(&ndlp->dhc_cfg.nlp_reauthfunc); +} + +/** + * lpfc_auth_start_tmr + * @ndlp: pointer to a node-list data structure. + * @value: timer value (in msecs). + * + * This routine cancels any pending reauthentication timer and updates + * the timer with a new value. This timer may also be used during the + * authentication process to check for auth_tmo. + * + **/ +void +lpfc_auth_start_tmr(struct lpfc_nodelist *ndlp, uint32_t value) +{ + struct lpfc_vport *vport = ndlp->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (ndlp->nlp_flag & NLP_AUTH_TMO) + lpfc_auth_cancel_tmr(ndlp); + + mod_timer(&ndlp->dhc_cfg.nlp_reauthfunc, + jiffies + msecs_to_jiffies(value)); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_AUTH_TMO; + spin_unlock_irq(shost->host_lock); +} + +/** + * lpfc_auth_start_reauth_tmr. + * @ndlp: pointer to a node-list data structure. + * + * Set-up timeout value for scheduled re-authentication. + **/ +void +lpfc_auth_start_reauth_tmr(struct lpfc_nodelist *ndlp) +{ + u32 msecs; + + msecs = ndlp->dhc_cfg.reauth_interval * 60000; + lpfc_auth_start_tmr(ndlp, msecs); +} + +/** + * lpfc_auth_findnode - Search for a nodelist item by wwpn pair. + * @vport: pointer to a vport structure. + * @lwwpn: pointer to a local portname. + * @rwwpn: pointer to a remote portname. + * + * This routine returns an node list pointer for authentication. The search + * uses local and remote portnames provided, with specially accomodation for + * the wwpn used to identify the fabric. The routine returns pointer to the + * matching ndlp or NULL if no matching entry is found. + **/ +struct lpfc_nodelist * +lpfc_auth_findnode(struct lpfc_vport *vport, struct lpfc_name *lwwpn, + struct lpfc_name *rwwpn) +{ + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_name wwpn; + + wwpn.u.name = AUTH_FABRIC_WWN; + if (!memcmp(&vport->fc_portname, lwwpn->u.wwn, 8)) { + if (!memcmp(wwpn.u.wwn, rwwpn->u.wwn, 8)) + ndlp = lpfc_findnode_did(vport, Fabric_DID); + else + ndlp = lpfc_findnode_wwpn(vport, rwwpn); + } + return ndlp; +} + +/** + * lpfc_auth_find_cfg_item - Search for a configuration entry by wwpn pair. + * @phba: pointer to a host. + * @lwwpn: pointer to a local portname. + * @rwwpn: pointer to a remote portname. + * @valid: address of entry valid flag. + * + * This routine returns a pointer to an active configuration entry matching + * the local and remote portnames provided, or NULL if no matching entry is + * found. + **/ +struct lpfc_auth_cfg_entry * +lpfc_auth_find_cfg_item(struct lpfc_hba *phba, uint8_t *lwwpn, uint8_t *rwwpn, + uint8_t *valid) +{ + struct lpfc_auth_cfg *pcfg = NULL; + struct lpfc_auth_cfg_entry *entry = NULL; + uint8_t *ptmp = NULL; + uint16_t entry_cnt, i; + + *valid = 0; + pcfg = lpfc_auth_get_active_cfg_ptr(phba); + if (!pcfg) + return entry; + + entry_cnt = pcfg->hdr.entry_cnt; + if (entry_cnt > MAX_AUTH_CONFIG_ENTRIES) + entry_cnt = MAX_AUTH_CONFIG_ENTRIES; + + ptmp = (uint8_t *)&pcfg->entry[0]; + for (i = 0; i < entry_cnt; i++) { + if (i == AUTH_CONFIG_ENTRIES_PER_PAGE) { + ptmp = (uint8_t *)lpfc_auth_get_active_cfg_p2(phba); + if (!ptmp) + return entry; + } + if ((memcmp(ptmp + 8, rwwpn, 8)) || + (memcmp(ptmp, lwwpn, 8))) { + ptmp += sizeof(struct lpfc_auth_cfg_entry); + } else { + entry = (struct lpfc_auth_cfg_entry *)ptmp; + /* match found, check validity */ + *valid = entry->auth_flags.valid; + break; + } + } + return entry; +} + +/** + * lpfc_auth_lookup_cfg - Set-up auth configuration information for an ndlp. + * @ndlp: pointer to lpfc_nodelist instance. + * + * This routine will initiate a search for a configuration entry matching the + * local wwpn and remote wwpn for the ndlp. Initial inplementation is limited + * to authentication with the fabric. If a configuration entry is found, the + * dh-chap configuration in the ndlp structure is populated. + * + * Return codes + * 0 - Success + * 1 - Failure + **/ +int +lpfc_auth_lookup_cfg(struct lpfc_nodelist *ndlp) +{ + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + struct lpfc_auth_cfg_entry *entry = NULL; + uint8_t rwwpn[8]; + uint8_t valid; + int i, rc = 0; + + /* limited to authentication with the fabric */ + u64_to_wwn(AUTH_FABRIC_WWN, rwwpn); + entry = lpfc_auth_find_cfg_item(phba, (uint8_t *)&vport->fc_portname, + rwwpn, &valid); + if (!entry || !valid) + return 1; + + ndlp->dhc_cfg.auth_tmo = entry->auth_tmo; + ndlp->dhc_cfg.auth_mode = entry->auth_mode; + ndlp->dhc_cfg.bidirectional = entry->auth_flags.bi_direction; + ndlp->dhc_cfg.reauth_interval = entry->reauth_interval; + ndlp->dhc_cfg.local_passwd_len = entry->pwd.local_pw_length; + ndlp->dhc_cfg.remote_passwd_len = entry->pwd.remote_pw_length; + ndlp->dhc_cfg.direction = AUTH_DIRECTION_NONE; + memcpy(ndlp->dhc_cfg.local_passwd, &entry->pwd.local_pw, + entry->pwd.local_pw_length); + memcpy(ndlp->dhc_cfg.remote_passwd, &entry->pwd.remote_pw, + entry->pwd.remote_pw_length); + for (i = 0; i < 4; i++) { + switch (entry->hash_priority[i]) { + case LPFC_HASH_MD5: + ndlp->dhc_cfg.hash_pri[i] = HASH_MD5; + break; + case LPFC_HASH_SHA1: + ndlp->dhc_cfg.hash_pri[i] = HASH_SHA1; + break; + default: + ndlp->dhc_cfg.hash_pri[i] = 0; + } + } + + ndlp->dhc_cfg.dh_grp_cnt = 0; + for (i = 0; i < 8; i++) { + switch (entry->dh_grp_priority[i]) { + case LPFC_DH_GROUP_2048: + ndlp->dhc_cfg.dh_grp_pri[i] = DH_GROUP_2048; + break; + case LPFC_DH_GROUP_1536: + ndlp->dhc_cfg.dh_grp_pri[i] = DH_GROUP_1536; + break; + case LPFC_DH_GROUP_1280: + ndlp->dhc_cfg.dh_grp_pri[i] = DH_GROUP_1280; + break; + case LPFC_DH_GROUP_1024: + ndlp->dhc_cfg.dh_grp_pri[i] = DH_GROUP_1024; + break; + case LPFC_DH_GROUP_NULL: + ndlp->dhc_cfg.dh_grp_pri[i] = DH_GROUP_NULL; + break; + default: + return rc; + } + ndlp->dhc_cfg.dh_grp_cnt++; + } + return rc; +} + +/** + * lpfc_auth_free_active_cfg_list - Free authentication config resources. + * @phba: pointer to a host. + * + * This routine frees any resources allocated to hold the driver's active + * copy of the authentication configuration object. + **/ +void +lpfc_auth_free_active_cfg_list(struct lpfc_hba *phba) +{ + struct lpfc_dmabuf *dmabuf, *next; + + if (!list_empty(&phba->lpfc_auth_active_cfg_list)) { + list_for_each_entry_safe(dmabuf, next, + &phba->lpfc_auth_active_cfg_list, + list) { + list_del(&dmabuf->list); + dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + } +} + +/** + * lpfc_auth_alloc_active_cfg_list - Allocate authentication config resources. + * @phba: pointer to a host. + * + * This routine attempts to allocate resources to hold the driver's active + * copy of the authentication configuration object. + * + * Return codes + * 0 - Success + * 1 - Failure + **/ +int +lpfc_auth_alloc_active_cfg_list(struct lpfc_hba *phba) +{ + struct lpfc_dmabuf *dmabuf; + uint8_t i; + int rc = 0; + + if (!list_empty(&phba->lpfc_auth_active_cfg_list)) + return -EINVAL; + + for (i = 0; i < 2; i++) { + dmabuf = kzalloc(sizeof(*dmabuf), GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + goto out; + } + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + SLI4_PAGE_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + rc = -ENOMEM; + goto out; + } + list_add_tail(&dmabuf->list, &phba->lpfc_auth_active_cfg_list); + } +out: + if (rc) + lpfc_auth_free_active_cfg_list(phba); + return rc; +} + +/** + * lpfc_auth_get_active_cfg_ptr - Returns the base address of the + * authentication config. + * @phba: pointer to a host. + * + * This routine returns a pointer to the first page of the driver's active copy + * of the authentication configuration for the port. The routine will return + * NULL if there is no active configuration. + * + **/ +struct lpfc_auth_cfg * +lpfc_auth_get_active_cfg_ptr(struct lpfc_hba *phba) +{ + struct lpfc_dmabuf *dmabuf; + struct lpfc_auth_cfg *p = NULL; + + if (!list_empty(&phba->lpfc_auth_active_cfg_list)) { + dmabuf = list_first_entry(&phba->lpfc_auth_active_cfg_list, + struct lpfc_dmabuf, list); + + p = (struct lpfc_auth_cfg *)dmabuf->virt; + } + return p; +} + +/** + * lpfc_auth_get_active_cfg_p2 - Returns the base address for the second page + * of the active authentication config. + * @phba: pointer to a host. + * + * This routine returns a pointer to the second page of the driver's active copy + * of the authentication configuration for the port. The routine will return + * NULL if there is no active configuation. + * + **/ +struct lpfc_auth_cfg_entry * +lpfc_auth_get_active_cfg_p2(struct lpfc_hba *phba) +{ + struct lpfc_dmabuf *dmabuf; + struct lpfc_auth_cfg_entry *p = NULL; + + if (!list_empty(&phba->lpfc_auth_active_cfg_list)) { + dmabuf = list_entry((&phba->lpfc_auth_active_cfg_list)->prev, + struct lpfc_dmabuf, list); + + p = (struct lpfc_auth_cfg_entry *)dmabuf->virt; + } + return p; +} + +/** + * lpfc_auth_cmpl_rd_object, completion for read object mbx cmd. + * @phba: pointer to a host. + * @mboxq: pointer to lpfc mailbox command context. + * + * This routine handles the completion of a read object mailbox command + * issued to populate the driver's active copy of the authentication + * configuration. + **/ +void +lpfc_auth_cmpl_rd_object(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_mbx_auth_rd_object *rd_object; + union lpfc_sli4_cfg_shdr *shdr; + uint32_t shdr_status, shdr_add_status; + int mb_sts = mboxq->u.mb.mbxStatus; + + rd_object = (struct lpfc_mbx_auth_rd_object *)mboxq->sge_array->addr[0]; + shdr = &rd_object->cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + + if (shdr_status || shdr_add_status || mb_sts) { + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_AUTH, + "3040 Read Object mailbox cmd failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, mb_sts); + + if (mboxq->ctx_buf == &phba->lpfc_auth_active_cfg_list) + lpfc_auth_free_active_cfg_list(phba); + } + + lpfc_sli4_mbox_cmd_free(phba, mboxq); +} + +/** + * lpfc_auth_read_cfg_object, to read object. + * @phba: pointer to a host. + * + * This routine issues a read object mailbox command to populate the driver's + * active copy of the authentication configuration. + * + * Return codes + * 0 - Success + * 1 - Failure + **/ +int +lpfc_auth_read_cfg_object(struct lpfc_hba *phba) +{ + uint32_t dma_size; + uint32_t offset; + char *obj_str = {"/driver/auth.cfg"}; + int rc = 0; + + if (list_empty(&phba->lpfc_auth_active_cfg_list)) + rc = lpfc_auth_alloc_active_cfg_list(phba); + if (rc) + return rc; + + /* 8k per port */ + dma_size = SLI4_PAGE_SIZE * 2; + offset = phba->sli4_hba.lnk_info.lnk_no * dma_size; + rc = lpfc_auth_issue_rd_object(phba, &phba->lpfc_auth_active_cfg_list, + dma_size, &offset, obj_str); + if (rc) { + /* MBX_BUSY is acceptable, no reason to alarm caller */ + if (rc == MBX_BUSY) + rc = MBX_SUCCESS; + else + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_AUTH, + "3041 Read Object abnormal exit:%x.\n", + rc); + } + if (rc != MBX_SUCCESS) + lpfc_auth_free_active_cfg_list(phba); + + return rc; +} + +/** + * lpfc_auth_compute_hash - Calculate the hash + * @vport: pointer to a host virtual N_Port data structure. + * + * Return value + * Pointer to hash + **/ +static uint8_t * +lpfc_auth_compute_hash(uint32_t hash_id, + uint8_t *val1, + uint32_t val1_len, + uint8_t *val2, + uint32_t val2_len, + uint8_t *val3, + uint32_t val3_len) +{ + struct crypto_shash *tfm = NULL; + struct shash_desc *desc = NULL; + uint8_t *digest = NULL; + uint32_t chal_len = 0; + int rc = 0; + + switch (hash_id) { + case HASH_MD5: + tfm = crypto_alloc_shash("md5", 0, 0); + chal_len = MD5_CHAL_LEN; + break; + case HASH_SHA1: + tfm = crypto_alloc_shash("sha1", 0, 0); + chal_len = SHA1_CHAL_LEN; + break; + default: + return NULL; + } + + if (!tfm) + return NULL; + + digest = kzalloc(chal_len, GFP_KERNEL); + if (!digest) + goto out; + + desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), + GFP_KERNEL); + if (!desc) { + rc = 1; + goto out; + } + desc->tfm = tfm; +#if (KERNEL_MAJOR < 5) + desc->flags = 0; +#endif + + rc = crypto_shash_init(desc); + if (rc < 0) + goto out; + if (val1 && val1_len) { + rc = crypto_shash_update(desc, val1, val1_len); + if (rc < 0) + goto out; + } + if (val2 && val2_len) { + rc = crypto_shash_update(desc, val2, val2_len); + if (rc < 0) + goto out; + } + if (val3 && val3_len) { + rc = crypto_shash_update(desc, val3, val3_len); + if (rc < 0) + goto out; + } + rc = crypto_shash_final(desc, digest); + +out: + if (rc) { + kfree(digest); + digest = NULL; + } + kfree(desc); + crypto_free_shash(tfm); + return digest; +} + +/** + * lpfc_auth_compute_dhkey - Calculate the dhkey + * @base: base value + * @base_len: base value length + * @expo: exponent value + * @expo_len: exponent value length + * @mod: modulo value + * @mod_len: modulo value length + * @key: resulting key value + * @key_len: resulting key value length + * + * Return value + * Success / Failure + **/ +static int +lpfc_auth_compute_dhkey(uint8_t *base, + uint32_t base_len, + uint8_t *expo, + uint32_t expo_len, + uint8_t *mod, + uint32_t mod_len, + uint8_t *key, + uint32_t key_len) +{ + int i, rc; + uint8_t *temp = NULL; + uint32_t temp_len = 0; + MPI k, b, e, m; + + /* + * key = ((base)^expo modulo mod) + */ + b = mpi_read_raw_data(base, base_len); + e = mpi_read_raw_data(expo, expo_len); + m = mpi_read_raw_data(mod, mod_len); + + k = mpi_alloc(mpi_get_nlimbs(m) * 2); + + rc = mpi_powm(k, b, e, m); + if (!rc) { + temp = mpi_get_buffer(k, &temp_len, NULL); + if (!temp) { + rc = 1; + goto out; + } + + if (key_len < temp_len) { + rc = 1; + goto out; + } + + /* Pad the key with leading zeros */ + memset(key, 0, key_len); + i = key_len - temp_len; + memcpy(key + i, temp, temp_len); + } + +out: + mpi_free(b); + mpi_free(e); + mpi_free(m); + mpi_free(k); + kfree(temp); + return rc; +} + +/** + * lpfc_auth_cmpl_negotiate - Completion callback routine + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + **/ +static void +lpfc_auth_cmpl_negotiate(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = phba->pport; + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_nodelist *ndlp = cmdiocb->context1; + + if (irsp->ulpStatus) + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3043 ELS_AUTH cmpl, ulpstatus=x%x/%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4]); + lpfc_els_free_iocb(phba, cmdiocb); + + if ((irsp->ulpStatus == IOSTAT_LS_RJT) && + ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->dhc_cfg.auth_mode == LPFC_AUTH_MODE_ACTIVE)) { + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; + /* logout should be sent on LS REJECT */ + lpfc_issue_els_logo(vport, ndlp, 0); + } +} + +/** + * lpfc_auth_issue_negotiate - Issue AUTH_NEGOTIATE command + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine issues AUTH_NEGOTIATE ELS command to the remote + * port as the authentication initiator. + * + * Return codes + * 0 - Success + * 1 - Failure + **/ +static int +lpfc_auth_issue_negotiate(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + uint8_t *pcmd; + struct lpfc_auth_hdr *hdr; + struct lpfc_auth_negotiate_cmn *negotiate; + struct lpfc_dhchap_param_cmn *dhchap_param; + struct lpfc_auth_param_hdr *param_hdr; + uint32_t param_len; + uint32_t *hash; + uint32_t *dh_group; + uint16_t cmdsize; + uint8_t i, dh_grp_cnt; + int rc; + + /* Support 2 Hash Functions and 5 DH-Groups */ + cmdsize = sizeof(struct lpfc_auth_hdr) + + sizeof(struct lpfc_auth_negotiate_cmn) + + sizeof(struct lpfc_dhchap_param_cmn) + + sizeof(struct lpfc_auth_param_hdr) + 2 * sizeof(uint32_t) + + sizeof(struct lpfc_auth_param_hdr) + 5 * sizeof(uint32_t); + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, ELS_CMD_AUTH); + + if (!elsiocb) + return 1; + + /* Save the auth details for later use */ + if (ndlp->dhc_cfg.state != LPFC_AUTH_SUCCESS) + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; + ndlp->dhc_cfg.msg = LPFC_AUTH_NEGOTIATE; + + pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + ndlp->dhc_cfg.tran_id += 1; + + /* Build the AUTH_NEGOTIATE header */ + hdr = (struct lpfc_auth_hdr *)pcmd; + hdr->auth_els_code = (uint8_t) ELS_CMD_AUTH; + hdr->auth_els_flags = 0; + hdr->auth_msg_code = AUTH_NEGOTIATE; + hdr->protocol_ver = AUTH_PROTOCOL_VER_1; + hdr->msg_len = be32_to_cpu(cmdsize - sizeof(struct lpfc_auth_hdr)); + hdr->tran_id = be32_to_cpu(ndlp->dhc_cfg.tran_id); + pcmd += sizeof(struct lpfc_auth_hdr); + + /* Set up AUTH_NEGOTIATE common data */ + negotiate = (struct lpfc_auth_negotiate_cmn *)pcmd; + negotiate->name_tag = be16_to_cpu(AUTH_NAME_TAG); + negotiate->name_len = be16_to_cpu(sizeof(struct lpfc_name)); + memcpy(&negotiate->port_name, &vport->fc_portname, + sizeof(struct lpfc_name)); + negotiate->num_protocol = be32_to_cpu(1); /* Only support DHCHAP */ + pcmd += sizeof(struct lpfc_auth_negotiate_cmn); + + /* Set up DH-CHAP parameters common data */ + dh_grp_cnt = ndlp->dhc_cfg.dh_grp_cnt; + if (dh_grp_cnt > 5) + dh_grp_cnt = 5; + dhchap_param = (struct lpfc_dhchap_param_cmn *)pcmd; + param_len = sizeof(uint32_t) + + sizeof(struct lpfc_auth_param_hdr) + 2 * sizeof(uint32_t) + + sizeof(struct lpfc_auth_param_hdr) + + dh_grp_cnt * sizeof(uint32_t); + dhchap_param->param_len = be32_to_cpu(param_len); + dhchap_param->protocol_id = be32_to_cpu(PROTOCOL_DHCHAP); + pcmd += sizeof(struct lpfc_dhchap_param_cmn); + + /* Set up Hash Functions */ + param_hdr = (struct lpfc_auth_param_hdr *)pcmd; + param_hdr->tag = be16_to_cpu(DHCHAP_TAG_HASHLIST); + param_hdr->wcnt = be16_to_cpu(2); /* 2 HASH Functions */ + pcmd += sizeof(struct lpfc_auth_param_hdr); + hash = (uint32_t *)pcmd; + hash[0] = be32_to_cpu(ndlp->dhc_cfg.hash_pri[0]); + hash[1] = be32_to_cpu(ndlp->dhc_cfg.hash_pri[1]); + pcmd += 2 * sizeof(uint32_t); + + /* Setup DH Groups */ + param_hdr = (struct lpfc_auth_param_hdr *)pcmd; + param_hdr->tag = be16_to_cpu(DHCHAP_TAG_GRP_IDLIST); + param_hdr->wcnt = be16_to_cpu(dh_grp_cnt); /* max 5 DH Groups */ + pcmd += sizeof(struct lpfc_auth_param_hdr); + dh_group = (uint32_t *)pcmd; + for (i = 0; i < dh_grp_cnt; i++) + dh_group[i] = be32_to_cpu(ndlp->dhc_cfg.dh_grp_pri[i]); + + elsiocb->iocb_cmpl = lpfc_auth_cmpl_negotiate; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + /* Set up authentication timer */ + if (ndlp->dhc_cfg.auth_tmo) + lpfc_auth_start_tmr(ndlp, ndlp->dhc_cfg.auth_tmo * 1000); + + return 0; +} + +/** + * lpfc_auth_issue_dhchap_challenge - Issue DHCHAP_CHALLENGE command + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine issues DHCHAP_CHALLENGE ELS command to the remote + * port as the authentication responder. + * + * Return codes + * 0 - Success + * 1 - Failure + **/ +static int +lpfc_auth_issue_dhchap_challenge(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_auth_hdr *hdr; + struct lpfc_auth_challenge *challenge; + uint8_t *pcmd; + uint16_t cmdsize; + uint32_t chal_len; + uint32_t hash_id = ndlp->dhc_cfg.hash_id; + uint32_t dh_grp_id = ndlp->dhc_cfg.dh_grp_id; + uint32_t dh_val_len = dh_group_array[dh_grp_id].length; + uint8_t nonce[16], key[256]; + uint8_t *rand_num = NULL; + uint32_t key_len; + uint8_t key_base = 2; + int rc = 0; + + switch (hash_id) { + case HASH_MD5: + chal_len = MD5_CHAL_LEN; + break; + case HASH_SHA1: + chal_len = SHA1_CHAL_LEN; + break; + default: + return 1; + } + + rand_num = kzalloc(chal_len, GFP_KERNEL); + if (!rand_num) { + rc = 1; + goto out; + } + get_random_bytes(rand_num, chal_len); + + cmdsize = sizeof(struct lpfc_auth_hdr) + + sizeof(struct lpfc_auth_challenge) + + chal_len + sizeof(uint32_t) + dh_val_len; + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, ELS_CMD_AUTH); + + if (!elsiocb) { + rc = 1; + goto out; + } + + pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + + /* Build the DHCHAP_REPLY payload */ + hdr = (struct lpfc_auth_hdr *)pcmd; + hdr->auth_els_code = (uint8_t) ELS_CMD_AUTH; + hdr->auth_els_flags = 0; + hdr->auth_msg_code = DHCHAP_CHALLENGE; + hdr->protocol_ver = AUTH_PROTOCOL_VER_1; + hdr->msg_len = be32_to_cpu(cmdsize - sizeof(struct lpfc_auth_hdr)); + hdr->tran_id = be32_to_cpu(ndlp->dhc_cfg.tran_id); + pcmd += sizeof(struct lpfc_auth_hdr); + + /* Set up DHCHAP_CHALLENGE payload */ + challenge = (struct lpfc_auth_challenge *)pcmd; + challenge->name_tag = be16_to_cpu(AUTH_NAME_TAG); + challenge->name_len = be16_to_cpu(sizeof(struct lpfc_name)); + memcpy(&challenge->port_name, &vport->fc_portname, + sizeof(struct lpfc_name)); + challenge->hash_id = be32_to_cpu(ndlp->dhc_cfg.hash_id); + challenge->dh_grp_id = be32_to_cpu(ndlp->dhc_cfg.dh_grp_id); + challenge->chal_len = be32_to_cpu(chal_len); + pcmd += sizeof(struct lpfc_auth_challenge); + memcpy(pcmd, rand_num, chal_len); + pcmd += chal_len; + *((uint32_t *)pcmd) = be32_to_cpu(dh_val_len); + pcmd += sizeof(uint32_t); + + /* Save the challenge */ + memcpy(ndlp->dhc_cfg.rand_num, rand_num, chal_len); + + if (dh_grp_id) { + key_len = dh_group_array[dh_grp_id].length; + get_random_bytes(nonce, sizeof(nonce)); + + rc = lpfc_auth_compute_dhkey(&key_base, sizeof(key_base), + nonce, sizeof(nonce), + dh_group_array[dh_grp_id].value, + dh_group_array[dh_grp_id].length, + key, key_len); + if (rc) + goto out; + + memcpy(pcmd, key, key_len); + + /* Save the nonce */ + memcpy(ndlp->dhc_cfg.nonce, nonce, sizeof(nonce)); + } + + elsiocb->iocb_cmpl = lpfc_auth_cmpl_negotiate; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + lpfc_els_free_iocb(phba, elsiocb); + +out: + kfree(rand_num); + return rc; +} + +/** + * lpfc_auth_issue_dhchap_reply - Issue DHCHAP_REPLY cmd + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_issue_dhchap_reply(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + uint32_t tran_id, uint32_t dh_grp_id, + uint32_t hash_id, uint8_t *hash_value, + uint8_t *dh_value, uint32_t dh_val_len) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_auth_hdr *hdr; + uint8_t *pcmd; + uint16_t cmdsize; + uint32_t chal_len = 0; + uint8_t *rand_num = NULL; + int rc = 0; + + switch (hash_id) { + case HASH_MD5: + /* Check for bi_directional support */ + if (ndlp->dhc_cfg.bidirectional) + chal_len = MD5_CHAL_LEN; + cmdsize = sizeof(struct lpfc_auth_hdr) + + sizeof(uint32_t) + MD5_CHAL_LEN + + sizeof(uint32_t) + dh_val_len + + sizeof(uint32_t) + chal_len; + break; + case HASH_SHA1: + /* Check for bi_directional support */ + if (ndlp->dhc_cfg.bidirectional) + chal_len = SHA1_CHAL_LEN; + cmdsize = sizeof(struct lpfc_auth_hdr) + + sizeof(uint32_t) + SHA1_CHAL_LEN + + sizeof(uint32_t) + dh_val_len + + sizeof(uint32_t) + chal_len; + break; + default: + return 1; + } + + ndlp->dhc_cfg.msg = LPFC_DHCHAP_REPLY; + + /* Check for bi_directional support before allocating rand_num */ + if (ndlp->dhc_cfg.bidirectional) { + rand_num = kzalloc(chal_len, GFP_KERNEL); + if (!rand_num) { + rc = 1; + goto out; + } + get_random_bytes(rand_num, chal_len); + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, ELS_CMD_AUTH); + + if (!elsiocb) { + rc = 1; + goto out; + } + + pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + + /* Build the DHCHAP_REPLY payload */ + hdr = (struct lpfc_auth_hdr *)pcmd; + hdr->auth_els_code = (uint8_t) ELS_CMD_AUTH; + hdr->auth_els_flags = 0; + hdr->auth_msg_code = DHCHAP_REPLY; + hdr->protocol_ver = AUTH_PROTOCOL_VER_1; + hdr->msg_len = be32_to_cpu(cmdsize - sizeof(struct lpfc_auth_hdr)); + hdr->tran_id = be32_to_cpu(tran_id); + + pcmd += sizeof(struct lpfc_auth_hdr); + if (hash_id == HASH_MD5) { + *((uint32_t *)pcmd) = be32_to_cpu(MD5_CHAL_LEN); + pcmd += sizeof(uint32_t); + memcpy(pcmd, hash_value, MD5_CHAL_LEN); + pcmd += MD5_CHAL_LEN; + } else if (hash_id == HASH_SHA1) { + *((uint32_t *)pcmd) = be32_to_cpu(SHA1_CHAL_LEN); + pcmd += sizeof(uint32_t); + memcpy(pcmd, hash_value, SHA1_CHAL_LEN); + pcmd += SHA1_CHAL_LEN; + } + + *((uint32_t *)pcmd) = be32_to_cpu(dh_val_len); + pcmd += sizeof(uint32_t); + if (dh_val_len) { + memcpy(pcmd, dh_value, dh_val_len); + pcmd += dh_val_len; + } + *((uint32_t *)pcmd) = be32_to_cpu(chal_len); + if (chal_len) { + pcmd += sizeof(uint32_t); + memcpy(pcmd, rand_num, chal_len); + } + + /* Save the auth details for later use */ + ndlp->dhc_cfg.hash_id = hash_id; + ndlp->dhc_cfg.tran_id = tran_id; + ndlp->dhc_cfg.dh_grp_id = dh_grp_id; + memcpy(ndlp->dhc_cfg.rand_num, rand_num, chal_len); + + elsiocb->iocb_cmpl = lpfc_auth_cmpl_negotiate; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + lpfc_els_free_iocb(phba, elsiocb); + + /* Set up authentication timer */ + if (ndlp->dhc_cfg.auth_tmo) + lpfc_auth_start_tmr(ndlp, ndlp->dhc_cfg.auth_tmo * 1000); +out: + kfree(rand_num); + return rc; +} + +/** + * lpfc_auth_issue_dhchap_success - Issue DHCHAP_SUCCESS cmd + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_issue_dhchap_success(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + uint8_t *hash_value) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_auth_hdr *hdr; + uint8_t *pcmd; + uint16_t cmdsize; + uint32_t chal_len = 0; + int rc = 0; + + if (ndlp->dhc_cfg.hash_id == HASH_MD5) + chal_len = MD5_CHAL_LEN; + else if (ndlp->dhc_cfg.hash_id == HASH_SHA1) + chal_len = SHA1_CHAL_LEN; + + cmdsize = sizeof(struct lpfc_auth_hdr) + sizeof(uint32_t); + if (hash_value) + cmdsize += chal_len; + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, ELS_CMD_AUTH); + + if (!elsiocb) { + rc = 1; + goto out; + } + + pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + + /* Build the DHCHAP_SUCCESS payload */ + hdr = (struct lpfc_auth_hdr *)pcmd; + hdr->auth_els_code = (uint8_t) ELS_CMD_AUTH; + hdr->auth_els_flags = 0; + hdr->auth_msg_code = DHCHAP_SUCCESS; + hdr->protocol_ver = AUTH_PROTOCOL_VER_1; + hdr->msg_len = be32_to_cpu(cmdsize - sizeof(struct lpfc_auth_hdr)); + hdr->tran_id = be32_to_cpu(ndlp->dhc_cfg.tran_id); + pcmd += sizeof(struct lpfc_auth_hdr); + + if (hash_value) { + *((uint32_t *)pcmd) = be32_to_cpu(chal_len); + pcmd += sizeof(uint32_t); + memcpy(pcmd, hash_value, chal_len); + } else { + *((uint32_t *)pcmd) = 0; + } + + elsiocb->iocb_cmpl = lpfc_auth_cmpl_negotiate; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + lpfc_els_free_iocb(phba, elsiocb); + + ndlp->dhc_cfg.state = LPFC_AUTH_SUCCESS; + ndlp->dhc_cfg.msg = LPFC_DHCHAP_SUCCESS_REPLY; + ndlp->dhc_cfg.direction = AUTH_DIRECTION_LOCAL; + ndlp->dhc_cfg.last_auth = jiffies; +out: + return rc; +} + +/** + * lpfc_auth_issue_reject - Issue AUTH_REJECT cmd + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * @tran_id: transaction id + * @rsn_code: reason code + * @rsn_expl: reason code explanation + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_issue_reject(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + uint32_t tran_id, + uint8_t rsn_code, + uint8_t rsn_expl) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_auth_hdr *hdr; + struct lpfc_auth_reject *rjt; + uint8_t *pcmd; + uint16_t cmdsize; + int rc = 0; + + cmdsize = sizeof(struct lpfc_auth_hdr) + sizeof(uint32_t); + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, ELS_CMD_AUTH); + + if (!elsiocb) { + rc = 1; + goto out; + } + + pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + + /* Build the AUTH_REJECT payload */ + hdr = (struct lpfc_auth_hdr *)pcmd; + hdr->auth_els_code = (uint8_t) ELS_CMD_AUTH; + hdr->auth_els_flags = 0; + hdr->auth_msg_code = AUTH_REJECT; + hdr->protocol_ver = AUTH_PROTOCOL_VER_1; + hdr->msg_len = be32_to_cpu(cmdsize - sizeof(struct lpfc_auth_hdr)); + hdr->tran_id = be32_to_cpu(tran_id); + + rjt = (struct lpfc_auth_reject *)(pcmd + sizeof(struct lpfc_auth_hdr)); + rjt->rsn_code = rsn_code; + rjt->rsn_expl = rsn_expl; + + elsiocb->iocb_cmpl = lpfc_auth_cmpl_negotiate; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) + lpfc_els_free_iocb(phba, elsiocb); + + ndlp->dhc_cfg.msg = LPFC_AUTH_REJECT; + ndlp->dhc_cfg.direction = AUTH_DIRECTION_NONE; +out: + return rc; +} + +/** + * lpfc_auth_handle_reject - Handle AUTH Reject for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @payload: pointer to AUTH Reject cmd payload. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_handle_reject(struct lpfc_vport *vport, uint8_t *payload, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_auth_reject *rjt; + uint8_t rsn_code; + uint8_t rsn_expl; + + rjt = (struct lpfc_auth_reject *) + (payload + sizeof(struct lpfc_auth_hdr)); + rsn_code = rjt->rsn_code; + rsn_expl = rjt->rsn_expl; + + if (rsn_code == AUTHRJT_LOGICAL_ERR && + rsn_expl == AUTHEXPL_RESTART_AUTH) { + /* Restart authentication */ + lpfc_auth_issue_negotiate(vport, ndlp); + } else { + ndlp->dhc_cfg.state = LPFC_AUTH_FAIL; + ndlp->dhc_cfg.msg = LPFC_AUTH_REJECT; + } + ndlp->dhc_cfg.direction = AUTH_DIRECTION_NONE; + + return 0; +} + +/** + * lpfc_auth_handle_negotiate - Handle AUTH Negotiate for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @payload: pointer to AUTH Negotiate cmd payload. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_handle_negotiate(struct lpfc_vport *vport, uint8_t *payload, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_auth_hdr *hdr; + struct lpfc_auth_negotiate_cmn *negotiate; + struct lpfc_dhchap_param_cmn *dhchap_param; + struct lpfc_auth_param_hdr *param_hdr; + uint32_t protocol_id, hash = 0, dh_group = 0; + uint8_t found = 0; + int i; + int rc = 0; + + hdr = (struct lpfc_auth_hdr *)payload; + + /* Nx_Port with the higher port_name shall remain the initiator */ + if (memcmp(&vport->fc_portname, &ndlp->nlp_portname, + sizeof(struct lpfc_name)) > 0) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_LOGICAL_ERR, + AUTHEXPL_AUTH_STARTED); + return 0; + } + + /* Sanity check the AUTH message header */ + if (hdr->protocol_ver != AUTH_PROTOCOL_VER_1) { + rc = 1; + goto out; + } + + /* Sanity check the Negotiate payload */ + payload += sizeof(struct lpfc_auth_hdr); + negotiate = (struct lpfc_auth_negotiate_cmn *)payload; + if (be16_to_cpu(negotiate->name_tag) != AUTH_NAME_TAG || + be16_to_cpu(negotiate->name_len) != sizeof(struct lpfc_name) || + be32_to_cpu(negotiate->num_protocol) == 0) { + rc = 1; + goto out; + } + + payload += sizeof(struct lpfc_auth_negotiate_cmn); + + /* Scan the payload for Protocol support */ + for (i = 0; i < be32_to_cpu(negotiate->num_protocol); i++) { + dhchap_param = (struct lpfc_dhchap_param_cmn *)payload; + protocol_id = be32_to_cpu(dhchap_param->protocol_id); + + if (protocol_id == PROTOCOL_DHCHAP) { + found = 1; + break; + } + + payload += be32_to_cpu(dhchap_param->param_len); + } + + if (!found) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_LOGICAL_ERR, + AUTHEXPL_MECH_UNUSABLE); + return 0; + } + + payload += sizeof(struct lpfc_dhchap_param_cmn); + param_hdr = (struct lpfc_auth_param_hdr *)payload; + payload += sizeof(struct lpfc_auth_param_hdr); + + /* Scan the payload for Hash support */ + found = 0; + for (i = 0; i < be32_to_cpu(param_hdr->wcnt); i++) { + hash = be32_to_cpu(*((uint32_t *)payload)); + + if (hash == HASH_MD5 || hash == HASH_SHA1) { + found = 1; + break; + } + + payload += sizeof(uint32_t); + } + + if (!found) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_LOGICAL_ERR, + AUTHEXPL_HASH_UNUSABLE); + return 0; + } + + param_hdr = (struct lpfc_auth_param_hdr *)payload; + payload += sizeof(struct lpfc_auth_param_hdr); + + /* Scan the payload for DH Group support */ + found = 0; + for (i = 0; i < be32_to_cpu(param_hdr->wcnt); i++) { + dh_group = be32_to_cpu(*((uint32_t *)payload)); + + if (dh_group >= DH_GROUP_NULL && dh_group <= DH_GROUP_2048) { + found = 1; + break; + } + + payload += sizeof(uint32_t); + } + + if (!found) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_LOGICAL_ERR, + AUTHEXPL_DHGRP_UNUSABLE); + return 0; + } + + /* Save the Authentication settings for this node */ + ndlp->dhc_cfg.tran_id = be32_to_cpu(hdr->tran_id); + ndlp->dhc_cfg.hash_id = hash; + ndlp->dhc_cfg.dh_grp_id = dh_group; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "6041 AUTH_NEGOTIATE " + "tran_id: x%x hash_id: x%x dh_grp: x%x\n", + be32_to_cpu(hdr->tran_id), hash, dh_group); + + /* Issue a DH-CHAP Challenge to the initiator */ + lpfc_auth_issue_dhchap_challenge(vport, ndlp); + return 0; + +out: + if (rc) + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; +} + +/** + * lpfc_auth_handle_dhchap_chal - Handle DHCHAP Challenge for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @payload: pointer to DHCHAP Challenge cmd payload. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_handle_dhchap_chal(struct lpfc_vport *vport, uint8_t *payload, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_auth_hdr *hdr; + struct lpfc_auth_challenge *chal; + uint8_t *hash_value = NULL; + uint32_t dh_val_len = 0; + uint8_t *dh_value = NULL; + uint8_t *aug_chal = NULL; + uint8_t challenge[20]; + uint8_t tran_id; + uint32_t hash_id; + uint32_t chal_len; + uint32_t dh_grp_id; + uint8_t nonce[16], key[256], rsp_key[256]; + uint32_t key_len; + uint32_t rsp_key_len; + uint8_t rsp_key_base = 2; + char *passwd = ndlp->dhc_cfg.local_passwd; + uint32_t passwd_len = ndlp->dhc_cfg.local_passwd_len; + int rc; + + hdr = (struct lpfc_auth_hdr *)payload; + /* Sanity check the AUTH message header */ + if (hdr->protocol_ver != AUTH_PROTOCOL_VER_1 || + be32_to_cpu(hdr->tran_id) != ndlp->dhc_cfg.tran_id) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + payload += sizeof(struct lpfc_auth_hdr); + chal = (struct lpfc_auth_challenge *)payload; + + tran_id = be32_to_cpu(hdr->tran_id) & 0xff; + hash_id = be32_to_cpu(chal->hash_id); + chal_len = be32_to_cpu(chal->chal_len); + dh_grp_id = be32_to_cpu(chal->dh_grp_id); + + payload += sizeof(struct lpfc_auth_challenge); + + ndlp->dhc_cfg.msg = LPFC_DHCHAP_CHALLENGE; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3044 AUTH_CHALLENGE " + "tran_id:x%x hash_id:x%x chal_len=x%x dh_grp=x%x\n", + tran_id, hash_id, chal_len, dh_grp_id); + + if (hash_id == HASH_MD5 && chal_len == MD5_CHAL_LEN) { + memcpy(challenge, payload, MD5_CHAL_LEN); + } else if (hash_id == HASH_SHA1 && chal_len == SHA1_CHAL_LEN) { + memcpy(challenge, payload, SHA1_CHAL_LEN); + } else { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + payload += chal_len; + + switch (dh_grp_id) { + case DH_GROUP_2048: + case DH_GROUP_1536: + case DH_GROUP_1280: + case DH_GROUP_1024: + key_len = dh_group_array[dh_grp_id].length; + rsp_key_len = dh_group_array[dh_grp_id].length; + /* Save the dh value */ + dh_val_len = be32_to_cpu(*((uint32_t *)payload)); + payload += sizeof(uint32_t); + + dh_value = kzalloc(dh_val_len, GFP_KERNEL); + if (!dh_value) + goto out; + memcpy(dh_value, payload, dh_val_len); + + /* Compute Ephemeral DH Key */ + get_random_bytes(nonce, sizeof(nonce)); + + rc = lpfc_auth_compute_dhkey(dh_value, dh_val_len, nonce, + sizeof(nonce), + dh_group_array[dh_grp_id].value, + dh_group_array[dh_grp_id].length, + key, key_len); + if (rc) + break; + + /* Save this key, (((g)^x)^y mod p) */ + memcpy(ndlp->dhc_cfg.dhkey, key, key_len); + ndlp->dhc_cfg.dhkey_len = key_len; + + rc = lpfc_auth_compute_dhkey(&rsp_key_base, + sizeof(rsp_key_base), + nonce, sizeof(nonce), + dh_group_array[dh_grp_id].value, + dh_group_array[dh_grp_id].length, + rsp_key, rsp_key_len); + if (rc) + break; + + /* + * Compute the augmented challenge + * aug_chal = hash(Challenge || Ephemeral DH Key) + */ + aug_chal = lpfc_auth_compute_hash(hash_id, challenge, chal_len, + key, key_len, 0, 0); + if (!aug_chal) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3045 Null aug_chal\n"); + break; + } + + /* Calculate the hash response */ + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + passwd, + passwd_len, + aug_chal, + chal_len); + break; + case DH_GROUP_NULL: + /* Calculate the hash response */ + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + passwd, + passwd_len, + challenge, + chal_len); + rsp_key_len = 0; + break; + default: + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, + AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + if (!hash_value) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3046 Null hash_value\n"); + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_AUTH_FAILED); + goto out; + } + + /* Issue DHCHAP reply */ + lpfc_auth_issue_dhchap_reply(vport, ndlp, be32_to_cpu(hdr->tran_id), + dh_grp_id, hash_id, hash_value, rsp_key, + rsp_key_len); + +out: + kfree(dh_value); + kfree(aug_chal); + kfree(hash_value); + return 0; +} + +/** + * lpfc_auth_handle_dhchap_reply - Handle DHCHAP Reply for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @payload: pointer to DHCHAP Challenge cmd payload. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_handle_dhchap_reply(struct lpfc_vport *vport, uint8_t *payload, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_auth_hdr *hdr; + uint8_t tran_id = ndlp->dhc_cfg.tran_id & 0xff; + uint32_t hash_id = ndlp->dhc_cfg.hash_id; + uint32_t dh_grp_id = ndlp->dhc_cfg.dh_grp_id; + uint32_t dh_val_len; + uint8_t dh_value[256], key[256]; + uint32_t resp_len; + uint32_t key_len = 0; + uint8_t resp_value[20]; + uint8_t *aug_chal = NULL; + uint8_t *hash_value = NULL; + uint8_t challenge[20]; + uint32_t chal_len; + char *local_passwd = ndlp->dhc_cfg.local_passwd; + uint32_t local_passwd_len = ndlp->dhc_cfg.local_passwd_len; + char *remote_passwd = ndlp->dhc_cfg.remote_passwd; + uint32_t remote_passwd_len = ndlp->dhc_cfg.remote_passwd_len; + int rc = 0; + + hdr = (struct lpfc_auth_hdr *)payload; + /* Sanity check the AUTH message header */ + if (hdr->protocol_ver != AUTH_PROTOCOL_VER_1 || + be32_to_cpu(hdr->tran_id) != ndlp->dhc_cfg.tran_id) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, + AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + payload += sizeof(struct lpfc_auth_hdr); + resp_len = be32_to_cpu(*(uint32_t *)payload); + payload += sizeof(uint32_t); + + if (hash_id == HASH_MD5 && resp_len == MD5_CHAL_LEN) { + memcpy(resp_value, payload, MD5_CHAL_LEN); + } else if (hash_id == HASH_SHA1 && resp_len == SHA1_CHAL_LEN) { + memcpy(resp_value, payload, SHA1_CHAL_LEN); + } else { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + payload += resp_len; + dh_val_len = be32_to_cpu(*(uint32_t *)payload); + payload += sizeof(uint32_t); + + if (dh_val_len != dh_group_array[dh_grp_id].length) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + memcpy(dh_value, payload, dh_val_len); + payload += dh_val_len; + + /* Check for bidirectional challenge */ + chal_len = be32_to_cpu(*(uint32_t *)payload); + payload += sizeof(uint32_t); + if (chal_len) { + if (chal_len != resp_len) { + lpfc_auth_issue_reject(vport, ndlp, + be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, + AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + memcpy(challenge, payload, chal_len); + /* compare this challenge with what was issued */ + if (!memcmp(challenge, ndlp->dhc_cfg.rand_num, chal_len)) { + lpfc_auth_issue_reject(vport, ndlp, + be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, + AUTHEXPL_BAD_PAYLOAD); + return 0; + } + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "6043 AUTH_REPLY tran_id: x%x hash_id: x%x " + "resp_len: x%x chal_len: x%x dh_grp: x%x\n", + tran_id, hash_id, resp_len, chal_len, dh_grp_id); + + switch (dh_grp_id) { + case DH_GROUP_2048: + case DH_GROUP_1536: + case DH_GROUP_1280: + case DH_GROUP_1024: + key_len = dh_group_array[dh_grp_id].length; + + /* Compute Ephemeral DH Key */ + rc = lpfc_auth_compute_dhkey(dh_value, dh_val_len, + ndlp->dhc_cfg.nonce, + sizeof(ndlp->dhc_cfg.nonce), + dh_group_array[dh_grp_id].value, + dh_group_array[dh_grp_id].length, + key, key_len); + if (rc) + break; + + /* + * Compute the augmented challenge + * aug_chal = hash(Challenge || Ephemeral DH Key) + */ + aug_chal = lpfc_auth_compute_hash(hash_id, + ndlp->dhc_cfg.rand_num, + resp_len, key, key_len, + 0, 0); + if (!aug_chal) { + rc = 1; + goto out; + } + + /* Calculate the hash response */ + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + remote_passwd, + remote_passwd_len, + aug_chal, + resp_len); + break; + case DH_GROUP_NULL: + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, sizeof(tran_id), + remote_passwd, + remote_passwd_len, + ndlp->dhc_cfg.rand_num, + resp_len); + break; + default: + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + if (!hash_value) { + rc = 1; + goto out; + } + + /* compare the hash with hash received from the remote port */ + if (memcmp(hash_value, resp_value, resp_len)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3047 Hash verification failed\n"); + rc = 1; + goto out; + } + + kfree(aug_chal); + aug_chal = NULL; + kfree(hash_value); + + /* Compute the response hash */ + if (dh_grp_id) { + /* + * Compute the augmented challenge + * aug_chal = hash(Challenge || Ephemeral DH Key) + */ + aug_chal = lpfc_auth_compute_hash(hash_id, + challenge, chal_len, + key, key_len, 0, 0); + + if (!aug_chal) { + rc = 1; + goto out; + } + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + local_passwd, + local_passwd_len, + aug_chal, + chal_len); + } else { + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + local_passwd, + local_passwd_len, + challenge, + chal_len); + } + + if (!hash_value) { + rc = 1; + goto out; + } + + lpfc_auth_issue_dhchap_success(vport, ndlp, hash_value); + +out: + kfree(aug_chal); + kfree(hash_value); + if (rc) + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_AUTH_FAILED); + return 0; +} + +/** + * lpfc_auth_handle_dhchap_success - Handle DHCHAP Success for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @payload: pointer to DHCHAP Challenge cmd payload. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +static int +lpfc_auth_handle_dhchap_success(struct lpfc_vport *vport, uint8_t *payload, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_auth_hdr *hdr; + uint32_t resp_len; + uint8_t *hash_value = NULL; + uint8_t *resp_value = NULL; + uint8_t *aug_chal = NULL; + uint8_t tran_id; + uint32_t hash_id; + uint32_t dh_grp_id; + uint32_t chal_len = 0; + char *local_passwd = ndlp->dhc_cfg.local_passwd; + uint32_t local_passwd_len = ndlp->dhc_cfg.local_passwd_len; + char *remote_passwd = ndlp->dhc_cfg.remote_passwd; + uint32_t remote_passwd_len = ndlp->dhc_cfg.remote_passwd_len; + int rc = 0; + + hdr = (struct lpfc_auth_hdr *)payload; + /* Sanity check the AUTH message header */ + if (hdr->protocol_ver != AUTH_PROTOCOL_VER_1 || + be32_to_cpu(hdr->tran_id) != ndlp->dhc_cfg.tran_id) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + payload += sizeof(struct lpfc_auth_hdr); + + tran_id = be32_to_cpu(hdr->tran_id) & 0xff; + resp_len = be32_to_cpu(*((uint32_t *)payload)); + resp_value = payload + sizeof(uint32_t); + + hash_id = ndlp->dhc_cfg.hash_id; + if (hash_id == HASH_MD5) { + chal_len = MD5_CHAL_LEN; + } else if (hash_id == HASH_SHA1) { + chal_len = SHA1_CHAL_LEN; + } else { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + dh_grp_id = ndlp->dhc_cfg.dh_grp_id; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3048 DHCHAP_SUCCESS resp_len = x%x, tran_id=x%x " + "hash_id=x%x\n", + resp_len, tran_id, hash_id); + if (resp_len) { + if (resp_len != chal_len) { + lpfc_auth_issue_reject(vport, ndlp, + be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, + AUTHEXPL_BAD_PAYLOAD); + return 0; + } + + if (dh_grp_id) { + /* + * Compute the augmented challenge + * aug_chal = hash(Challenge || Ephemeral DH Key) + */ + aug_chal = + lpfc_auth_compute_hash(hash_id, + ndlp->dhc_cfg.rand_num, + chal_len, + ndlp->dhc_cfg.dhkey, + ndlp->dhc_cfg.dhkey_len, + 0, 0); + if (!aug_chal) { + rc = 1; + goto out; + } + + /* Calculate the hash response */ + hash_value = lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + remote_passwd, + remote_passwd_len, + aug_chal, + chal_len); + } else { + /* Calculate the hash response */ + hash_value = + lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + remote_passwd, + remote_passwd_len, + ndlp->dhc_cfg.rand_num, + chal_len); + } + + if (!hash_value) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3049 Null hash_value\n"); + rc = 1; + goto out; + } + + /* compare the hash with hash received from the remote port */ + if (memcmp(hash_value, resp_value, resp_len)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_AUTH, + "3100 Hash verification failed\n"); + rc = 1; + goto out; + } + + if (!dh_grp_id) { + /* test for identical local and remote secrets */ + hash_value = + lpfc_auth_compute_hash(hash_id, + &tran_id, + sizeof(tran_id), + local_passwd, + local_passwd_len, + ndlp->dhc_cfg.rand_num, + chal_len); + if (!hash_value) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_AUTH, + "3014 Null hash_value\n"); + rc = 1; + goto out; + } + if (!memcmp(hash_value, resp_value, resp_len)) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_AUTH, + "3101 Local and Remote " + "secrets must differ.\n"); + rc = 1; + goto out; + } + } + + lpfc_auth_issue_dhchap_success(vport, ndlp, NULL); + + } else { + ndlp->dhc_cfg.state = LPFC_AUTH_SUCCESS; + ndlp->dhc_cfg.last_auth = jiffies; + } + ndlp->dhc_cfg.msg = LPFC_DHCHAP_SUCCESS; + ndlp->dhc_cfg.direction |= AUTH_DIRECTION_REMOTE; +out: + kfree(aug_chal); + kfree(hash_value); + if (rc) { + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_AUTH_FAILED); + lpfc_issue_els_logo(vport, ndlp, 0); + } + return 0; +} + +/** + * lpfc_auth_handle_cmd - Handle unsolicited auth cmd for a vport + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - + * 1 - + **/ +int +lpfc_auth_handle_cmd(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + uint8_t *pcmd = NULL; + uint32_t size, size1 = 0, size2 = 0; + struct lpfc_auth_hdr *hdr; + struct ulp_bde64 *pbde; + int rc = 0; + + size = cmdiocb->iocb.unsli3.rcvsli3.acc_len; + pcmd = kzalloc(size, GFP_KERNEL); + if (!pcmd) + goto out; + + size1 = cmdiocb->iocb.un.cont64[0].tus.f.bdeSize; + memcpy(pcmd, ((struct lpfc_dmabuf *)cmdiocb->context2)->virt, size1); + if (cmdiocb->iocb.ulpBdeCount == 2) { + pbde = (struct ulp_bde64 *)&cmdiocb->iocb.unsli3.sli3Words[4]; + size2 = pbde->tus.f.bdeSize; + memcpy(pcmd + size1, + ((struct lpfc_dmabuf *)cmdiocb->context3)->virt, size2); + } + + lpfc_auth_cancel_tmr(ndlp); + hdr = (struct lpfc_auth_hdr *)pcmd; + + switch (hdr->auth_msg_code) { + case AUTH_REJECT: + rc = lpfc_auth_handle_reject(vport, pcmd, ndlp); + break; + case AUTH_NEGOTIATE: + rc = lpfc_auth_handle_negotiate(vport, pcmd, ndlp); + break; + case AUTH_DONE: + /* Nothing to do */ + break; + case DHCHAP_CHALLENGE: + rc = lpfc_auth_handle_dhchap_chal(vport, pcmd, ndlp); + break; + case DHCHAP_REPLY: + rc = lpfc_auth_handle_dhchap_reply(vport, pcmd, ndlp); + break; + case DHCHAP_SUCCESS: + rc = lpfc_auth_handle_dhchap_success(vport, pcmd, ndlp); + if (!rc) { + /* Authentication complete */ + if (vport->port_state < LPFC_VPORT_READY) { + if (vport->port_state != LPFC_FDISC) + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } + + /* Set up reauthentication timer */ + if (ndlp->dhc_cfg.reauth_interval) + lpfc_auth_start_reauth_tmr(ndlp); + } + break; + default: + lpfc_auth_issue_reject(vport, ndlp, be32_to_cpu(hdr->tran_id), + AUTHRJT_FAILURE, AUTHEXPL_BAD_PAYLOAD); + break; + } + +out: + kfree(pcmd); + return rc; +} + +/** + * lpfc_auth_start - Start DH-CHAP authentication + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine initiates authentication on the @vport. + * + * Return codes + * 0 - Authentication required before logins continue + * 1 - No Authentication will be done + **/ +int +lpfc_auth_start(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + uint8_t fcsp_en; + int rc = 0; + + if (!phba->cfg_enable_auth) + return 1; + + if (phba->sli4_hba.fawwpn_in_use) + return 1; + + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return 1; + + /* + * If FC_DISC_DELAYED is set, delay the authentication. + */ + spin_lock_irq(shost->host_lock); + if (vport->fc_flag & FC_DISC_DELAYED) { + spin_unlock_irq(shost->host_lock); + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "3435 Delay authentication for %d seconds\n", + phba->fc_ratov); + mod_timer(&vport->delayed_disc_tmo, + jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); + return 0; + } + spin_unlock_irq(shost->host_lock); + + fcsp_en = (ndlp->nlp_DID == Fabric_DID) ? phba->fc_fabparam.cmn.fcsp : + ndlp->fc_sparam.cmn.fcsp; + + /* Determine the dh-chap configuration for port pair */ + rc = lpfc_auth_lookup_cfg(ndlp); + if (rc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_AUTH, + "3042 No Authentication configuration found " + "for request.\n"); + + if (fcsp_en) { + ndlp->dhc_cfg.state = LPFC_AUTH_FAIL; + lpfc_issue_els_logo(vport, ndlp, 0); + return 0; + } + return 1; + } + + switch (ndlp->dhc_cfg.auth_mode) { + case LPFC_AUTH_MODE_PASSIVE: + if (!fcsp_en) + return 1; + /* Fall Thru */ + case LPFC_AUTH_MODE_ACTIVE: + rc = lpfc_auth_issue_negotiate(vport, ndlp); + if (rc) + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; + break; + case LPFC_AUTH_MODE_DISABLE: + if (!fcsp_en) + return 1; + /* fall through */ + default: + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; + /* logout should be sent */ + lpfc_issue_els_logo(vport, ndlp, 0); + } + + return rc; +} + +/** + * lpfc_auth_reauth - Restart DH-CHAP authentication + * @ptr: pointer to a node-list data structure. + * + * This routine initiates authentication on the @vport. + * + **/ +void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_auth_reauth(unsigned long ptr) +#else +lpfc_auth_reauth(struct timer_list *t) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)ptr; +#else + struct lpfc_nodelist *ndlp = from_timer(ndlp, t, + dhc_cfg.nlp_reauthfunc); +#endif + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + unsigned long flags; + struct lpfc_work_evt *evtp = &ndlp->reauth_evt; + + spin_lock_irqsave(&phba->hbalock, flags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + /* We need to hold the node by incrementing the reference + * count until the queued work is done + */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (evtp->evt_arg1) { + evtp->evt = LPFC_EVT_REAUTH; + list_add_tail(&evtp->evt_listp, &phba->work_list); + lpfc_worker_wake_up(phba); + } + spin_unlock_irqrestore(&phba->hbalock, flags); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_AUTH, + "3102 Start Reauthentication\n"); +} + +/** + * lpfc_auth_timeout_handler - process authentication timer expiry + * @vport: pointer to a host virtual N_Port data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine authentication will clean up an incomplete authentication + * or start reauthentication. + * + **/ +void +lpfc_auth_timeout_handler(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_work_evt *evtp; + + /* determine whether previous authentication completed */ + if (ndlp->dhc_cfg.msg == LPFC_DHCHAP_SUCCESS) { + lpfc_auth_start(vport, ndlp); + } else { + ndlp->dhc_cfg.state = LPFC_AUTH_FAIL; + ndlp->dhc_cfg.msg = LPFC_AUTH_REJECT; + ndlp->dhc_cfg.direction = AUTH_DIRECTION_NONE; + + if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) + return; + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + del_timer_sync(&ndlp->nlp_delayfunc); + ndlp->nlp_last_elscmd = 0; + if (!list_empty(&ndlp->els_retry_evt.evt_listp)) { + list_del_init(&ndlp->els_retry_evt.evt_listp); + /* Decrement ndlp ref count held for delayed retry */ + evtp = &ndlp->els_retry_evt; + lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); + } + } +} + diff --git a/drivers/scsi/lpfc/lpfc_auth.h b/drivers/scsi/lpfc/lpfc_auth.h new file mode 100644 index 000000000..9edd01f23 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_auth.h @@ -0,0 +1,222 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2018 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.broadcom.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ +/* See Fibre Channel protocol T11 FC-SP-2 for details */ + +/* AUTH_ELS Message header */ +struct lpfc_auth_hdr { + uint8_t auth_els_code; /* 0x90 */ + uint8_t auth_els_flags; + uint8_t auth_msg_code; + uint8_t protocol_ver; /* version = 1 */ + uint32_t msg_len; /* msg payload len */ + uint32_t tran_id; /* transaction id */ +}; + +/* protocol_ver defines */ +#define AUTH_PROTOCOL_VER_1 0x1 + +/* auth_msg_code defines */ +#define AUTH_REJECT 0x0A +#define AUTH_NEGOTIATE 0x0B +#define AUTH_DONE 0x0C +#define DHCHAP_CHALLENGE 0x10 +#define DHCHAP_REPLY 0x11 +#define DHCHAP_SUCCESS 0x12 + +/* Auth Parameter Header */ +struct lpfc_auth_param_hdr { + uint16_t tag; + uint16_t wcnt; +}; + +struct lpfc_dhchap_param_cmn { + uint32_t param_len; + uint32_t protocol_id; /* DH-CHAP = 1 */ + /* DH-CHAP specific */ + /* variable length data */ +}; + +/* AUTH_ELS Negotiate payload */ +struct lpfc_auth_negotiate_cmn { + uint16_t name_tag; /* tag = 1 */ + uint16_t name_len; /* len = 8 */ + uint32_t port_name[2]; /* WWPN */ + uint32_t num_protocol; /* only 1 protocol for now */ + /* Protocol specific */ + /* variable length data */ +}; + +/* name_tag defines */ +#define AUTH_NAME_TAG 1 + +/* protocol_id defines */ +#define PROTOCOL_DHCHAP 1 +#define PROTOCOL_FCAP 2 +#define PROTOCOL_FCPAP 3 +#define PROTOCOL_KERBEROS 4 + +/* DHCHAP param tag defines */ +#define DHCHAP_TAG_HASHLIST 1 +#define DHCHAP_TAG_GRP_IDLIST 2 + +/* DHCHAP Group ID defines */ +#define DH_GROUP_NULL 0x00 +#define DH_GROUP_1024 0x01 +#define DH_GROUP_1280 0x02 +#define DH_GROUP_1536 0x03 +#define DH_GROUP_2048 0x04 + +/* hash function defines */ +#define HASH_MD5 5 +#define HASH_SHA1 6 + +#define MD5_CHAL_LEN 16 +#define SHA1_CHAL_LEN 20 + +#define AUTH_DIRECTION_NONE 0 +#define AUTH_DIRECTION_REMOTE 1 +#define AUTH_DIRECTION_LOCAL 2 +#define AUTH_DIRECTION_BIDI (AUTH_DIRECTION_LOCAL | AUTH_DIRECTION_REMOTE) + +#define AUTH_FABRIC_WWN 0xFFFFFFFFFFFFFFFFLL + +enum auth_state { + LPFC_AUTH_UNKNOWN = 0, + LPFC_AUTH_SUCCESS = 1, + LPFC_AUTH_FAIL = 2, +}; + +enum auth_msg_state { + LPFC_AUTH_NONE = 0, + LPFC_AUTH_REJECT = 1, /* Sent a Reject */ + LPFC_AUTH_NEGOTIATE = 2, /* Auth Negotiate */ + LPFC_DHCHAP_CHALLENGE = 3, /* Challenge */ + LPFC_DHCHAP_REPLY = 4, /* Reply */ + LPFC_DHCHAP_SUCCESS_REPLY = 5, /* Success with Reply */ + LPFC_DHCHAP_SUCCESS = 6, /* Success */ + LPFC_AUTH_DONE = 7, +}; + +#define LPFC_AUTH_STATE_UNKNOWN 0 +#define LPFC_AUTH_STATE_SUCCESS 1 +#define LPFC_AUTH_STATE_FAIL 2 + +#define DHC_STATE_AUTH_NEGO 1 +#define DHC_STATE_AUTH_CHAL 2 +#define DHC_STATE_AUTH_REPLY 3 +#define DHC_STATE_AUTH_SUCCESS 4 +#define DHC_STATE_AUTH_FAIL 5 + +/* AUTH_ELS Challenge payload */ +struct lpfc_auth_challenge { + uint16_t name_tag; /* tag = 1 */ + uint16_t name_len; /* len = 8 */ + uint32_t port_name[2]; /* WWPN */ + uint32_t hash_id; /* Hash function id */ + uint32_t dh_grp_id; /* DH_Group id */ + uint32_t chal_len; /* Challenge length */ + /* Variable length data */ +}; + +/* AUTH Reject reason code defines */ +#define AUTHRJT_FAILURE 1 +#define AUTHRJT_LOGICAL_ERR 2 + +/* AUTH Reject reason code explanation defines */ +#define AUTHEXPL_MECH_UNUSABLE 1 +#define AUTHEXPL_DHGRP_UNUSABLE 2 +#define AUTHEXPL_HASH_UNUSABLE 3 +#define AUTHEXPL_AUTH_STARTED 4 +#define AUTHEXPL_AUTH_FAILED 5 +#define AUTHEXPL_BAD_PAYLOAD 6 +#define AUTHEXPL_BAD_PROTOCOL 7 +#define AUTHEXPL_RESTART_AUTH 8 + +/* AUTH_ELS Reject payload */ +struct lpfc_auth_reject { + uint8_t rsn_code; + uint8_t rsn_expl; + uint8_t rsvd[2]; +}; + +struct dh_group { + uint32_t groupid; + uint32_t length; + uint8_t value[256]; +}; + +#define LPFC_AUTH_PSSWD_MAX_LEN 128 +struct lpfc_auth_pwd_entry { + uint8_t local_pw_length; + uint8_t local_pw_mode; + uint8_t remote_pw_length; + uint8_t remote_pw_mode; + uint8_t local_pw[LPFC_AUTH_PSSWD_MAX_LEN]; + uint8_t remote_pw[LPFC_AUTH_PSSWD_MAX_LEN]; +}; + +struct lpfc_auth_cfg_hdr { + uint32_t signature; + uint8_t version; + uint8_t size; + uint16_t entry_cnt; +}; + +struct lpfc_auth_cfg_entry { + uint8_t local_wwn[8]; + uint8_t remote_wwn[8]; + uint16_t auth_tmo; +#define LPFC_AUTH_MODE_DISABLE 1 +#define LPFC_AUTH_MODE_ACTIVE 2 +#define LPFC_AUTH_MODE_PASSIVE 3 + uint8_t auth_mode; +#define LPFC_AUTH_BIDIR_DISABLE 0 +#define LPFC_AUTH_BIDIR_ENABLE 1 + struct { + uint8_t bi_direction : 1; + uint8_t rsvd : 6; + uint8_t valid : 1; + } auth_flags; + uint8_t auth_priority[4]; +#define LPFC_HASH_MD5 1 +#define LPFC_HASH_SHA1 2 + uint8_t hash_priority[4]; +#define LPFC_DH_GROUP_NULL 1 +#define LPFC_DH_GROUP_1024 2 +#define LPFC_DH_GROUP_1280 3 +#define LPFC_DH_GROUP_1536 4 +#define LPFC_DH_GROUP_2048 5 + uint8_t dh_grp_priority[8]; + uint32_t reauth_interval; + struct lpfc_auth_pwd_entry pwd; +}; + +#define LPFC_AUTH_OBJECT_MAX_SIZE 0x8000 +#define MAX_AUTH_CONFIG_ENTRIES 16 +#define AUTH_CONFIG_ENTRIES_PER_PAGE ((SLI4_PAGE_SIZE - \ + sizeof(struct lpfc_auth_cfg_hdr)) / sizeof(struct lpfc_auth_cfg_entry)) + +struct lpfc_auth_cfg { + struct lpfc_auth_cfg_hdr hdr; + struct lpfc_auth_cfg_entry entry[MAX_AUTH_CONFIG_ENTRIES]; +}; + diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 6c2b03415..2d7c88257 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -34,6 +33,9 @@ #include #include #include +#ifndef NO_APEX +#include +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -49,6 +51,9 @@ #include "lpfc_debugfs.h" #include "lpfc_vport.h" #include "lpfc_version.h" +#ifndef BUILD_BRCMFCOE +#include "lpfc_auth.h" +#endif struct lpfc_bsg_event { struct list_head node; @@ -278,6 +283,328 @@ lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers, return bytes_copied; } +#ifndef NO_APEX +/** + * lpfc_chk_param - memcmp two fields. + * @prta: uint8_t pointer. + * @prtb: uint8_t pointer. + * @size: size to compare. + * returns 1 if equal, 0 if not equal + **/ +static int +lpfc_chk_params(uint8_t *ptra, uint8_t *ptrb, int size) +{ + return memcmp(ptra, ptrb, size) == 0; +} + +/** + * lpfc_chk_wwpn - memcmp two port names. + * @prta: uint8_t pointer to portname. + * @prtb: uint8_t pointer to portname. + * @size: size to compare. + * returns 1 if equal, 0 if not equal + **/ +static int +lpfc_chk_wwpn(uint8_t *ptra, uint8_t *ptrb, int size) +{ + return lpfc_chk_params(ptra, ptrb, size); +} + +/** + * lpfc_chk_lun - memcmp two luns. + * @prta: uint8_t pointer to ist lun. + * @prtb: uint8_t pointer to 2nd lun. + * @size: size to compare. + * returns 1 if equal, 0 if not equal + **/ +static int +lpfc_chk_lun(uint8_t *ptra, uint8_t *ptrb, int size) +{ + return lpfc_chk_params(ptra, ptrb, size); +} + +/** + * lpfc_conv_lun - convert fcp lun to scsi lun.. + * @prta: uint8_t pointer to fcp lun. + * returns lun as an integer. + **/ +static int +lpfc_conv_lun(uint8_t *fcp_lun) +{ + return scsilun_to_int((struct scsi_lun *)fcp_lun); +} + +/** + * lpfc_set_ndlp_fcp_pri - set the fcp priority for the lun range. + * @vport: lpfc_vport pointer. + * @first_lunr: 1st lun. + * @last_lun: last lun in the range. + * @fcp_priority: fcp priority level + * This function sets the priority level for the effected lun range in + * the ndlps fcp_priority arrary. + **/ +static void +lpfc_set_ndlp_fcp_pri(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + int first_lun, int last_lun, + uint8_t fcp_priority) +{ + int i = 0; + uint8_t pri = 0; + int lun_offset = 0; + + for (i = first_lun; i <= last_lun; i++) { + if (i == 0) + lun_offset = 0; + else + lun_offset = i >> 1; + pri = ndlp->fcp_priority[lun_offset]; + if (i & 1) + pri = ((pri & 0x0f) | (fcp_priority << 4)); + else + pri = ((pri & 0xf0) | fcp_priority); + ndlp->fcp_priority[lun_offset] = pri; + } +} + +/** + * lpfc_apply_fcp_priority_rule - set the fcp priority I/T nexus. + * @vport: lpfc_vport pointer. + * @rule: fcp_priority rule. + * This function walks the vports ndlp list and calls lpfc_set_ndlp_fcp_pri + * to apply the rule to the ndlp + **/ +static void +lpfc_apply_fcp_priority_rule(struct lpfc_vport *vport, + struct lpfc_fcp_pri_rule *rule) +{ + int wild_src = 0; + int wild_tgt = 0; + int wild_first_lun = 0; + int wild_last_lun = 0; + uint64_t wild_card; + uint8_t *wild; + int first_lun = 0; + int last_lun = 0; + struct lpfc_nodelist *ndlp; + + wild_card = (uint64_t) -1; + wild = (uint8_t *) &wild_card; + wild_src = lpfc_chk_wwpn(rule->src_wwpn, wild, + sizeof(rule->src_wwpn)); + if (!wild_src && !lpfc_chk_wwpn(rule->src_wwpn, + (uint8_t *)&vport->fc_portname, + sizeof(rule->src_wwpn))) + return; /* this rule does not apply to this vport */ + wild_tgt = lpfc_chk_wwpn(rule->tgt_wwpn, wild, + sizeof(rule->tgt_wwpn)); + wild_first_lun = lpfc_chk_lun(rule->first_lun, wild, + sizeof(rule->first_lun)); + wild_last_lun = lpfc_chk_lun(rule->last_lun, wild, + sizeof(rule->last_lun)); + if (!wild_first_lun) { + first_lun = lpfc_conv_lun(rule->first_lun); + if (first_lun > vport->cfg_max_luns) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3032 Bad 1st lun:%d in FCP rule\n", + first_lun); + return; + } + } + + if (!wild_last_lun) + last_lun = lpfc_conv_lun(rule->first_lun); + else + last_lun = vport->cfg_max_luns; + if (last_lun > vport->cfg_max_luns) + last_lun = vport->cfg_max_luns; + + if (!wild_tgt) { + ndlp = lpfc_findnode_wwpn(vport, + (struct lpfc_name *)rule->tgt_wwpn); + if ((!ndlp) || !(ndlp->nlp_type & NLP_FCP_TARGET)) + return; /* The target has not been discovered yet */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_MISC, + "3072 Applying fcp_priority:%d to" + " I=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " + " T=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" + " luns:0x%x - 0x%x\n", + rule->fcp_priority, + vport->fc_portname.u.wwn[0], + vport->fc_portname.u.wwn[1], + vport->fc_portname.u.wwn[2], + vport->fc_portname.u.wwn[3], + vport->fc_portname.u.wwn[4], + vport->fc_portname.u.wwn[5], + vport->fc_portname.u.wwn[6], + vport->fc_portname.u.wwn[7], + ndlp->nlp_portname.u.wwn[0], + ndlp->nlp_portname.u.wwn[1], + ndlp->nlp_portname.u.wwn[2], + ndlp->nlp_portname.u.wwn[3], + ndlp->nlp_portname.u.wwn[4], + ndlp->nlp_portname.u.wwn[5], + ndlp->nlp_portname.u.wwn[6], + ndlp->nlp_portname.u.wwn[7], + first_lun, last_lun); + lpfc_set_ndlp_fcp_pri(vport, ndlp, first_lun, last_lun, + rule->fcp_priority); + } else { + /* walk the vports list of ndlp's and set the priority. */ + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (!(ndlp->nlp_type & NLP_FCP_TARGET)) + continue; + lpfc_printf_vlog(vport, KERN_INFO, LOG_MISC, + "3090 Applying fcp_priority:%d to" + " I=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " + " T=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" + " luns:0x%x - 0x%x\n", + rule->fcp_priority, + vport->fc_portname.u.wwn[0], + vport->fc_portname.u.wwn[1], + vport->fc_portname.u.wwn[2], + vport->fc_portname.u.wwn[3], + vport->fc_portname.u.wwn[4], + vport->fc_portname.u.wwn[5], + vport->fc_portname.u.wwn[6], + vport->fc_portname.u.wwn[7], + ndlp->nlp_portname.u.wwn[0], + ndlp->nlp_portname.u.wwn[1], + ndlp->nlp_portname.u.wwn[2], + ndlp->nlp_portname.u.wwn[3], + ndlp->nlp_portname.u.wwn[4], + ndlp->nlp_portname.u.wwn[5], + ndlp->nlp_portname.u.wwn[6], + ndlp->nlp_portname.u.wwn[7], + first_lun, last_lun); + + lpfc_set_ndlp_fcp_pri(vport, ndlp, first_lun, last_lun, + rule->fcp_priority); + } + } + return; +} + +/** + * lpfc_set_fcp_priority - set the fcp priority for each rule. + * @phba: lpfc_hba pointer. + * @rules: fcp_priority rules list. + * This function walks the rules list and attempts to apply them to every vport + * and ndlp. + **/ +static void +lpfc_set_fcp_priority(struct lpfc_hba *phba, struct lpfc_fcp_pri_rules *rules) +{ + struct lpfc_vport **vports; + int i = 0; + int j = 0; + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (j = rules->number_of_entries - 1; j >= 0; j--) { + for (i = 0; + i <= phba->max_vports && vports[i] != NULL; + i++) { + lpfc_apply_fcp_priority_rule(vports[i], + &rules->rule_entry[j]); + } + } + lpfc_destroy_vport_work_array(phba, vports); + } +} + +/** + * lpfc_set_fcp_priority - set the fcp priority for each rule. + * @phba: lpfc_hba pointer. + * @rules: fcp_priority rules list. + * This function walks the rules list and attempts to apply them to every vport + * and ndlp. + **/ +void +lpfc_set_ndlps_fcp_priority(struct lpfc_nodelist *ndlp) +{ + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba; + struct lpfc_fcp_pri_rules *rules; + int j = 0; + int istgt = 0; + int isinit = 0; + uint64_t wild_card; + uint8_t *wild; + + if (!vport) + return; + phba = vport->phba; + if (!phba) + return; + if (!phba->fcp_priority_rules) + return; + rules = phba->fcp_priority_rules; + if (!rules) + return; + wild_card = (uint64_t) -1; + wild = (uint8_t *) &wild_card; + for (j = rules->number_of_entries - 1; j >= 0; j--) { + isinit = lpfc_chk_wwpn(rules->rule_entry[j].src_wwpn, wild, + sizeof(rules->rule_entry[j].src_wwpn)); + if (!isinit) + isinit = lpfc_chk_wwpn(rules->rule_entry[j].src_wwpn, + (uint8_t *)&vport->fc_portname, + sizeof(rules->rule_entry[j].src_wwpn)); + + istgt = lpfc_chk_wwpn(rules->rule_entry[j].tgt_wwpn, wild, + sizeof(rules->rule_entry[j].tgt_wwpn)); + if (!istgt) + istgt = lpfc_chk_wwpn(rules->rule_entry[j].tgt_wwpn, + (uint8_t *)&ndlp->nlp_portname, + sizeof(rules->rule_entry[j].tgt_wwpn)); + if (istgt && isinit) + lpfc_apply_fcp_priority_rule(vport, + &rules->rule_entry[j]); + } +} + +/** + * lpfc_clr_ndlps_pri - clear the fcp priority for each target. + * @vport: lpfc_vport pointer. + * This function walks the ndlp list and for this vport and clears + * all of the fcp_priority. + **/ +static void +lpfc_clr_ndlps_pri(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp; + + /* walk the vports list of ndlp's and sent the priority. */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3070 lpc_clr_ndlps_pri: fcp_priority sz = %d\n", + (int)sizeof(ndlp->fcp_priority)); + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + memset(ndlp->fcp_priority, 0, sizeof(ndlp->fcp_priority)); + } + return; +} + +/** + * lpfc_clr_vports_fcp_priority - clear the fcp priority for each vport. + * @phba: lpfc_hba pointer. + * This function walks the list of vports and calls lpfc_clr_ndlps_pri. + **/ +static void +lpfc_clr_vports_fcp_prority(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + int i = 0; + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; + i++) { + lpfc_clr_ndlps_pri(vports[i]); + } + lpfc_destroy_vport_work_array(phba, vports); + } +} +#endif + /** * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler * @phba: Pointer to HBA context object. @@ -641,6 +968,7 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, } lpfc_nlp_put(ndlp); + cmdiocbq->iocb_flag &= ~LPFC_IO_RAW; lpfc_els_free_iocb(phba, cmdiocbq); kfree(dd_data); @@ -675,6 +1003,9 @@ lpfc_bsg_rport_els(struct bsg_job *job) unsigned long flags; uint32_t creg_val; int rc = 0; + uint32_t did; + uint32_t *ptr; + uint32_t raw_data[2]; /* in case no data is transferred */ bsg_reply->reply_payload_rcv_len = 0; @@ -698,11 +1029,46 @@ lpfc_bsg_rport_els(struct bsg_job *job) } elscmd = bsg_request->rqst_data.r_els.els_code; - cmdsize = job->request_payload.payload_len; - if (!lpfc_nlp_get(ndlp)) { - rc = -ENODEV; - goto free_dd_data; + /* Check for raw ELS data as opposed to a specific command */ + if (elscmd == ELS_CMD_RAW) { + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + raw_data, sizeof(raw_data)); + + /* The first word indicates raw data, the second is the did */ + did = raw_data[1]; + + /* Now find an appropriate ndlp */ + if (did != ndlp->nlp_DID) { + ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) { + ndlp = lpfc_nlp_init(vport, did); + if (!ndlp) { + rc = -ENODEV; + goto free_dd_data; + } + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) { + rc = -ENODEV; + goto free_dd_data; + } + } + } + + /* The raw data that forms the ELS command starts at word 2 */ + cmdsize = job->request_payload.payload_len - + (2 * sizeof(uint32_t)); + } else { + did = ndlp->nlp_DID; + if (!lpfc_nlp_get(ndlp)) { + rc = -ENODEV; + goto free_dd_data; + } + cmdsize = job->request_payload.payload_len; } /* We will use the allocated dma buffers by prep els iocb for command @@ -712,20 +1078,35 @@ lpfc_bsg_rport_els(struct bsg_job *job) */ cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, - ndlp->nlp_DID, elscmd); + did, elscmd); if (!cmdiocbq) { rc = -EIO; goto release_ndlp; } - rpi = ndlp->nlp_rpi; - /* Transfer the request payload to allocated command dma buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, - cmdsize); + job->request_payload.payload_len); + + /* Check for raw ELS data as opposed to a specific command */ + if (elscmd == ELS_CMD_RAW) { + cmdiocbq->iocb_flag |= LPFC_IO_RAW; + + /* The raw data for the ELS command starts ar word 2, + * so shift the entire payload back 2 words. + */ + ptr = (uint32_t *) + ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt; + while (cmdsize > 0) { + *ptr = *(ptr + 2); + ptr++; + cmdsize -= sizeof(uint32_t); + } + } + + rpi = ndlp->nlp_rpi; if (phba->sli_rev == LPFC_SLI_REV4) cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; @@ -939,28 +1320,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); - if (piocbq->iocb.ulpBdeCount == 0 || - piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) - goto error_ct_unsol_exit; - - if (phba->link_state == LPFC_HBA_ERROR || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) - goto error_ct_unsol_exit; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - dmabuf = bdeBuf1; - else { - dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, - piocbq->iocb.un.cont64[0].addrLow); - dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); - } - if (dmabuf == NULL) - goto error_ct_unsol_exit; - ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; + ct_req = (struct lpfc_sli_ct_request *)bdeBuf1->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { @@ -1618,6 +1980,231 @@ no_dd_data: return rc; } +#ifndef NO_APEX +/** + * lpfc_bsg_set_fcp_priority - process a bsg vendor command + * @job: BSG_SET_FCP_PRIORITY fc_bsg_job + **/ +static int +lpfc_bsg_set_fcp_priority(struct bsg_job *job) +{ + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct set_lpfc_fcp_pri_rules *command; + int len; + int copied; + int rc = 0; + struct lpfc_fcp_pri_rules *myrule; + + + /* in case no data is transferred */ + bsg_reply->reply_payload_rcv_len = 0; + + /* check request len */ + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct set_lpfc_fcp_pri_rules)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3078 Received GET_FCP_PRI request below " + "minimum size\n"); + rc = -EINVAL; + goto set_fcp_priority_exit_1; + } + + /* check reply len */ + if (job->reply_len < sizeof(*bsg_reply)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3079 Received GET_FCP_PRI reply below " + "minimum size\n"); + rc = -EINVAL; + goto set_fcp_priority_exit_1; + } + + /* point to the vendor command */ + command = (struct set_lpfc_fcp_pri_rules *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + + /* app adding an extra beyond what we already have */ + if (command->number_of_entries > LPFC_MAX_FCP_SET_RULES) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3074 Received GET_FCP_PRI reply below " + "minimum size\n"); + rc = -EINVAL; + goto set_fcp_priority_exit_1; + } + + /* get size of rules data, add one extra for adds */ + len = (int)sizeof(struct lpfc_fcp_pri_rules) + + (command->number_of_entries * + sizeof(struct lpfc_fcp_pri_rule)); + myrule = kmalloc(len, GFP_KERNEL); + if (!myrule) { + rc = -ENOMEM; + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "9009 No memory for rules \n"); + goto set_fcp_priority_exit_1; + } + if (command->number_of_entries > 0) { + len = (int)sizeof(struct lpfc_fcp_pri_rules) + + (command->number_of_entries * + sizeof(struct lpfc_fcp_pri_rule)); + copied = sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, myrule, len); + if (len != copied) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3075 Received GET_FCP_PRI reply below " + "minimum size\n"); + rc = -EINVAL; + goto set_fcp_priority_exit_2; + } + + } else + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3069 Clearing FCP rules\n"); + if (phba->fcp_priority_rules) { + lpfc_clr_vports_fcp_prority(phba); + kfree(phba->fcp_priority_rules); + phba->fcp_priority_rules = NULL; + } + if (command->number_of_entries > 0) { + phba->fcp_priority_rules = myrule; + lpfc_set_fcp_priority(phba, myrule); + } else + kfree(myrule); + + job->dd_data = NULL; + bsg_reply->result = 0; + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + return 0; + +set_fcp_priority_exit_2: + kfree(myrule); +set_fcp_priority_exit_1: + /* make error code available to userspace */ + bsg_reply->result = rc; + job->dd_data = NULL; + return rc; +} + +/** + * lpfc_bsg_get_fcp_priority - process a bsg vendor command + * @job: BSG_GET_FCP_PRIORITY fc_bsg_job + **/ +static int +lpfc_bsg_get_fcp_priority(struct bsg_job *job) +{ + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + int rc = 0; + struct get_lpfc_fcp_pri_rules *command; + int len; + struct lpfc_fcp_pri_rules *myrule; + + /* get size of dummy data */ + len = (int)sizeof(struct lpfc_fcp_pri_rules); + myrule = kmalloc(len, GFP_KERNEL); + if (!myrule) { + rc = -ENOMEM; + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3071 no memory for priority rules\n"); + goto get_fcp_priority_exit1; + } + if (phba->fcp_priority_rules) + myrule->number_of_entries = + phba->fcp_priority_rules->number_of_entries; + else + myrule->number_of_entries = 0; + + /* in case no data is transferred */ + bsg_reply->reply_payload_rcv_len = 0; + + /* check request len */ + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct get_lpfc_fcp_pri_rules)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3073 Received GET_FCP_PRI request below " + "minimum size\n"); + rc = -EINVAL; + goto get_fcp_priority_exit; + } + + /* check reply len */ + if (job->reply_len < sizeof(*bsg_reply) + + sizeof(struct get_lpfc_fcp_pri_rules_reply)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3076 Received GET_FCP_PRI reply below " + "minimum size\n"); + rc = -EINVAL; + goto get_fcp_priority_exit; + } + + /* point to the vendor command */ + command = (struct get_lpfc_fcp_pri_rules *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + + /* app wants more rules than we have */ + if (phba->fcp_priority_rules && (command->number_of_entries > + phba->fcp_priority_rules->number_of_entries)) + len = (int)sizeof(struct lpfc_fcp_pri_rules) + + (phba->fcp_priority_rules->number_of_entries * + sizeof(struct lpfc_fcp_pri_rule)); + /* app wants some or all of our rules */ + else if (phba->fcp_priority_rules && command->number_of_entries > 0) + len = (int)sizeof(struct lpfc_fcp_pri_rules) + + (command->number_of_entries * + sizeof(struct lpfc_fcp_pri_rule)); + /* app is fishing for how many rules we have */ + else + /* return just the count of rules */ + len = (int)sizeof(struct lpfc_fcp_pri_rules); + if (len == (int)sizeof(struct lpfc_fcp_pri_rules)) { + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + myrule, len); + } else { + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + phba->fcp_priority_rules, len); + } + + if (bsg_reply->reply_payload_rcv_len != len) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3077 Received GET_FCP_PRI reply below " + "minimum size data:%d %d %d %d %d\n", + bsg_reply->reply_payload_rcv_len, + len, command->number_of_entries, + job->request_payload.sg_cnt, + myrule->number_of_entries); + bsg_reply->reply_payload_rcv_len = 0; + rc = -EINVAL; + goto get_fcp_priority_exit; + } + + kfree(myrule); + job->dd_data = NULL; + bsg_reply->result = rc; + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + return 0; + +get_fcp_priority_exit: + kfree(myrule); +get_fcp_priority_exit1: + /* make error code available to userspace */ + bsg_reply->result = rc; + job->dd_data = NULL; + return rc; +} +#endif + /** * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command * @job: SEND_MGMT_RESP fc_bsg_job @@ -2404,33 +2991,27 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) union lpfc_sli4_cfg_shdr *shdr; uint32_t shdr_status, shdr_add_status; struct diag_status *diag_status_reply; - int mbxstatus, rc = 0; + int mbxstatus, rc = -ENODEV, rc1 = 0; shost = fc_bsg_to_shost(job); - if (!shost) { - rc = -ENODEV; + if (!shost) goto job_error; - } - vport = shost_priv(shost); - if (!vport) { - rc = -ENODEV; - goto job_error; - } - phba = vport->phba; - if (!phba) { - rc = -ENODEV; - goto job_error; - } - if (phba->sli_rev < LPFC_SLI_REV4) { - rc = -ENODEV; + vport = shost_priv(shost); + if (!vport) goto job_error; - } + + phba = vport->phba; + if (!phba) + goto job_error; + + + if (phba->sli_rev < LPFC_SLI_REV4) + goto job_error; + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < - LPFC_SLI_INTF_IF_TYPE_2) { - rc = -ENODEV; + LPFC_SLI_INTF_IF_TYPE_2) goto job_error; - } if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct sli4_link_diag)) { @@ -2457,16 +3038,20 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) goto job_error; pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) + if (!pmboxq) { + rc = -ENOMEM; goto link_diag_test_exit; + } req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - sizeof(struct lpfc_sli4_cfg_mhdr)); alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) + if (alloc_len != req_len) { + rc = -ENOMEM; goto link_diag_test_exit; + } run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, @@ -2498,13 +3083,12 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) diag_status_reply = (struct diag_status *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*diag_status_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "3012 Received Run link diag test reply " "below minimum size (%d): reply_len:%d\n", - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct diag_status)), + (int)(sizeof(*bsg_reply) + + sizeof(*diag_status_reply)), job->reply_len); rc = -EINVAL; goto job_error; @@ -2515,7 +3099,7 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) diag_status_reply->shdr_add_status = shdr_add_status; link_diag_test_exit: - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); + rc1 = lpfc_sli4_bsg_set_link_diag_state(phba, 0); if (pmboxq) mempool_free(pmboxq, phba->mbox_mem_pool); @@ -2524,6 +3108,8 @@ link_diag_test_exit: job_error: /* make error code available to userspace */ + if (rc1 && !rc) + rc = rc1; bsg_reply->result = rc; /* complete the job back to userspace if no error */ if (rc == 0) @@ -2916,6 +3502,9 @@ diag_cmd_data_alloc(struct lpfc_hba *phba, if (nocopydata) { bpl->tus.f.bdeFlags = 0; + pci_dma_sync_single_for_device(phba->pcidev, + dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); + } else { memset((uint8_t *)dmp->dma.virt, 0, cnt); bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; @@ -3099,8 +3688,8 @@ static int lpfc_bsg_diag_loopback_run(struct bsg_job *job) { struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); - struct fc_bsg_reply *bsg_reply = job->reply; struct lpfc_hba *phba = vport->phba; + struct fc_bsg_reply *bsg_reply = job->reply; struct lpfc_bsg_event *evt; struct event_data *evdat; struct lpfc_sli *psli = &phba->sli; @@ -3403,8 +3992,8 @@ static int lpfc_bsg_get_dfc_rev(struct bsg_job *job) { struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); - struct fc_bsg_reply *bsg_reply = job->reply; struct lpfc_hba *phba = vport->phba; + struct fc_bsg_reply *bsg_reply = job->reply; struct get_mgmt_rev_reply *event_reply; int rc = 0; @@ -3420,8 +4009,7 @@ lpfc_bsg_get_dfc_rev(struct bsg_job *job) event_reply = (struct get_mgmt_rev_reply *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2741 Received GET_DFC_REV reply below " "minimum size\n"); @@ -3454,8 +4042,8 @@ static void lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { struct bsg_job_data *dd_data; - struct fc_bsg_reply *bsg_reply; struct bsg_job *job; + struct fc_bsg_reply *bsg_reply; uint32_t size; unsigned long flags; uint8_t *pmb, *pmb_buf; @@ -3691,7 +4279,7 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) bsg_reply->result = 0; lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2937 SLI_CONFIG ext-buffer mailbox command " + "2937 SLI_CONFIG ext-buffer maibox command " "(x%x/x%x) complete bsg job done, bsize:%d\n", phba->mbox_ext_buf_ctx.nembType, phba->mbox_ext_buf_ctx.mboxType, size); @@ -3702,7 +4290,7 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); } else { lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2938 SLI_CONFIG ext-buffer mailbox " + "2938 SLI_CONFIG ext-buffer maibox " "command (x%x/x%x) failure, rc:x%x\n", phba->mbox_ext_buf_ctx.nembType, phba->mbox_ext_buf_ctx.mboxType, rc); @@ -3736,7 +4324,7 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) pmboxq->u.mb.mbxStatus = MBXERR_ERROR; lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2939 SLI_CONFIG ext-buffer rd mailbox command " + "2939 SLI_CONFIG ext-buffer rd maibox command " "complete, ctxState:x%x, mbxStatus:x%x\n", phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); @@ -3752,6 +4340,7 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); } + return; } @@ -3776,7 +4365,7 @@ lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) pmboxq->u.mb.mbxStatus = MBXERR_ERROR; lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2940 SLI_CONFIG ext-buffer wr mailbox command " + "2940 SLI_CONFIG ext-buffer wr maibox command " "complete, ctxState:x%x, mbxStatus:x%x\n", phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); @@ -4058,12 +4647,12 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "2947 Issued SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); return SLI_CONFIG_HANDLED; } lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "2948 Failed to issue SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); rc = -EPIPE; job_error: @@ -4217,12 +4806,12 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "2955 Issued SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); return SLI_CONFIG_HANDLED; } lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "2956 Failed to issue SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); rc = -EPIPE; goto job_error; } @@ -4306,6 +4895,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: case COMN_OPCODE_GET_CNTL_ATTRIBUTES: case COMN_OPCODE_GET_PROFILE_CONFIG: + case COMN_OPCODE_SET_FEATURES: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3106 Handled SLI_CONFIG " "subsys_comn, opcode:x%x\n", @@ -4489,6 +5079,12 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, phba->mbox_ext_buf_ctx.seqNum++; nemb_tp = phba->mbox_ext_buf_ctx.nembType; + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + rc = -ENOMEM; + goto job_error; + } + pbuf = (uint8_t *)dmabuf->virt; size = job->request_payload.payload_len; sg_copy_to_buffer(job->request_payload.sg_list, @@ -4525,13 +5121,6 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, "2968 SLI_CONFIG ext-buffer wr all %d " "ebuffers received\n", phba->mbox_ext_buf_ctx.numBuf); - - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - rc = -ENOMEM; - goto job_error; - } - /* mailbox command structure for base driver */ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) { @@ -4563,12 +5152,12 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "2969 Issued SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); return SLI_CONFIG_HANDLED; } lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "2970 Failed to issue SLI_CONFIG ext-buffer " - "mailbox command, rc:x%x\n", rc); + "maibox command, rc:x%x\n", rc); rc = -EPIPE; goto job_error; } @@ -4580,8 +5169,6 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, return SLI_CONFIG_HANDLED; job_error: - if (pmboxq) - mempool_free(pmboxq, phba->mbox_mem_pool); lpfc_bsg_dma_page_free(phba, dmabuf); kfree(dd_data); @@ -5017,9 +5604,9 @@ static int lpfc_bsg_mbox_cmd(struct bsg_job *job) { struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; struct fc_bsg_request *bsg_request = job->request; struct fc_bsg_reply *bsg_reply = job->reply; - struct lpfc_hba *phba = vport->phba; struct dfc_mbox_req *mbox_req; int rc = 0; @@ -5177,9 +5764,9 @@ static int lpfc_menlo_cmd(struct bsg_job *job) { struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; struct fc_bsg_request *bsg_request = job->request; struct fc_bsg_reply *bsg_reply = job->reply; - struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocbq; IOCB_t *cmd; int rc = 0; @@ -5203,8 +5790,8 @@ lpfc_menlo_cmd(struct bsg_job *job) goto no_dd_data; } - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { + if (job->reply_len < sizeof(*bsg_reply) + + sizeof(struct menlo_response)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2785 Received MENLO_CMD reply below " "minimum size\n"); @@ -5340,8 +5927,7 @@ no_dd_data: static int lpfc_forced_link_speed(struct bsg_job *job) { - struct Scsi_Host *shost = fc_bsg_to_shost(job); - struct lpfc_vport *vport = shost_priv(shost); + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); struct lpfc_hba *phba = vport->phba; struct fc_bsg_reply *bsg_reply = job->reply; struct forced_link_speed_support_reply *forced_reply; @@ -5360,9 +5946,7 @@ lpfc_forced_link_speed(struct bsg_job *job) forced_reply = (struct forced_link_speed_support_reply *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + - sizeof(struct forced_link_speed_support_reply)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*forced_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "0049 Received FORCED_LINK_SPEED reply below " "minimum size\n"); @@ -5381,6 +5965,811 @@ job_error: return rc; } +#ifndef BUILD_BRCMFCOE +/** + * lpfc_manage_auth_update_obj - Update the auth configuration in flash. + * @phba: Pointer to HBA context object. + * @buf - Pointer to the object name to be updated. + * + * This function reads the existing flash configuration and rewrites + * the object, saving the active configuration for the port. + **/ +static int +lpfc_manage_auth_update_obj(struct lpfc_hba *phba, uint8_t *buf) +{ + struct list_head dma_buffer_list; + struct lpfc_dmabuf *dmabuf, *next; + struct lpfc_auth_cfg *dcfg = NULL; + struct lpfc_auth_cfg_entry *dcfg_p2 = NULL; + int i, bcnt; + uint32_t offset, temp_offset; + char *obj_name = (char *)buf; + int rc = 0; + + /* create buffer list and allocate buffers */ + bcnt = LPFC_AUTH_OBJECT_MAX_SIZE / SLI4_PAGE_SIZE; + INIT_LIST_HEAD(&dma_buffer_list); + for (i = 0; i < bcnt; i++) { + dmabuf = kzalloc(sizeof(*dmabuf), GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + goto release_out; + } + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + SLI4_PAGE_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + rc = -ENOMEM; + goto release_out; + } + list_add_tail(&dmabuf->list, &dma_buffer_list); + } + + /* read capture the entire object */ + offset = 0; + rc = lpfc_auth_rd_object(phba, &dma_buffer_list, + LPFC_AUTH_OBJECT_MAX_SIZE, &offset, obj_name); + if (rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC | LOG_AUTH, + "3108 Read Object failed, status:%x.\n", rc); + rc = LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + goto release_out; + } + + /* update with driver config for this port */ + offset = phba->sli4_hba.lnk_info.lnk_no * SLI4_PAGE_SIZE * 2; + dcfg = lpfc_auth_get_active_cfg_ptr(phba); + dcfg_p2 = lpfc_auth_get_active_cfg_p2(phba); + if (!dcfg || !dcfg_p2) + return LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + + temp_offset = 0; + list_for_each_entry(dmabuf, &dma_buffer_list, list) { + if (temp_offset == offset) + memcpy(dmabuf->virt, dcfg, SLI4_PAGE_SIZE); + else if (temp_offset == offset + SLI4_PAGE_SIZE) + memcpy(dmabuf->virt, dcfg_p2, SLI4_PAGE_SIZE); + + temp_offset += SLI4_PAGE_SIZE; + } + + /* write back the entire object */ + offset = 0; + rc = lpfc_auth_wr_object(phba, &dma_buffer_list, + LPFC_AUTH_OBJECT_MAX_SIZE, &offset, obj_name); + if (rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC | LOG_AUTH, + "3109 Write Object failed, status:%x.\n", rc); + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + } +release_out: + list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { + list_del(&dmabuf->list); + dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + return rc; +} + +/** + * lpfc_manage_auth_pwd_fetch - Return password information. + * @phba: Pointer to HBA context object. + * @buf - Pointer to a password descriptor. + * @src - Argument specifying the password information source. + * 0 - active (driver) configuration. + * 1 - saved (flash) configuration. + * + * This function returns password information, if available, for + * a configuration entry matching the wwpn pair described by the + * password descriptor. The src parameter specifies whether the + * saved or active configuration values are to be used. + **/ +static int +lpfc_manage_auth_pwd_fetch(struct lpfc_hba *phba, uint8_t *buf, + uint8_t src) +{ + struct lpfc_bsg_auth_pwd_item *pbuf; + struct list_head dmabuf_list; + struct lpfc_dmabuf *dmabuf, *next; + struct lpfc_auth_cfg *pcfg = NULL; + struct lpfc_auth_cfg_entry *ptmp; + struct lpfc_auth_cfg_entry *ptmp_p2 = NULL; + struct lpfc_auth_cfg_entry *entry = NULL; + uint32_t offset; + uint8_t i, valid; + char *obj_name = {"/driver/auth.cfg"}; + int rc = 0; + + pbuf = (struct lpfc_bsg_auth_pwd_item *)buf; + if (!pbuf) + return LPFC_BSG_AUTH_STS_GENERAL_ERROR; + + if (src) { + /* use the configuration from flash */ + INIT_LIST_HEAD(&dmabuf_list); + for (i = 0; i < 2; i++) { + dmabuf = kzalloc(sizeof(*dmabuf), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + SLI4_PAGE_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + rc = -ENOMEM; + goto release_out; + } + if (i) + ptmp_p2 = (struct lpfc_auth_cfg_entry *) + dmabuf->virt; + else + pcfg = (struct lpfc_auth_cfg *)dmabuf->virt; + + list_add_tail(&dmabuf->list, &dmabuf_list); + } + + offset = phba->sli4_hba.lnk_info.lnk_no * SLI4_PAGE_SIZE * 2; + rc = lpfc_auth_rd_object(phba, &dmabuf_list, + SLI4_PAGE_SIZE * 2, &offset, + obj_name); + if (rc || offset < sizeof(struct lpfc_auth_cfg_hdr)) { + rc = LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + goto release_out; + } + + ptmp = &pcfg->entry[0]; + for (i = 0; i < pcfg->hdr.entry_cnt; i++, ptmp++) { + if (i == AUTH_CONFIG_ENTRIES_PER_PAGE) + ptmp = ptmp_p2; + + /* look for matching wwpn pair */ + if (!memcmp(&ptmp->local_wwn[0], + &pbuf->lwwpn[0], 8) && + !memcmp(&ptmp->remote_wwn[0], + &pbuf->rwwpn[0], 8)) { + entry = ptmp; + break; + } + } + } else + entry = lpfc_auth_find_cfg_item(phba, &pbuf->lwwpn[0], + &pbuf->rwwpn[0], &valid); + + if (entry) { + if ((entry->pwd.local_pw_mode == 0) || + (entry->pwd.local_pw_mode > 2) || + (entry->pwd.local_pw_length == 0) || + (entry->pwd.local_pw[0] == 0)) + pbuf->local.type = 3; + else { + pbuf->local.type = entry->pwd.local_pw_mode; + pbuf->local.length = entry->pwd.local_pw_length; + memcpy(&pbuf->local.pwd[0], + &entry->pwd.local_pw[0], + LPFC_AUTH_PSSWD_MAX_LEN); + } + if ((entry->pwd.remote_pw_mode == 0) || + (entry->pwd.remote_pw_mode > 2) || + (entry->pwd.remote_pw_length == 0) || + (entry->pwd.remote_pw[0] == 0)) + + pbuf->remote.type = 3; + else { + pbuf->remote.type = entry->pwd.remote_pw_mode; + pbuf->remote.length = entry->pwd.remote_pw_length; + memcpy(&pbuf->remote.pwd[0], + &entry->pwd.remote_pw[0], + LPFC_AUTH_PSSWD_MAX_LEN); + } + } else { + rc = LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + } + +release_out: + if (src) + list_for_each_entry_safe(dmabuf, next, &dmabuf_list, list) { + list_del(&dmabuf->list); + dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + + return rc; +} + +/** + * lpfc_manage_auth_password_update - Update password information. + * @phba: Pointer to HBA context object. + * @buf - Pointer to a password information structure. + * + * This function updates password information, for a lwwpn/rwwpn pair + * described in the password information structure. + **/ +static int +lpfc_manage_auth_pwd_update(struct lpfc_vport *vport, uint8_t *buf) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_bsg_auth_pwd_item *pbuf; + struct lpfc_auth_cfg *pcfg = NULL; + struct lpfc_auth_cfg_entry *entry = NULL; + struct lpfc_nodelist *ndlp = NULL; + uint8_t valid; + int rc = 0; + + pbuf = (struct lpfc_bsg_auth_pwd_item *)buf; + if (!pbuf) + return LPFC_BSG_AUTH_STS_GENERAL_ERROR; + + if (list_empty(&phba->lpfc_auth_active_cfg_list)) { + rc = lpfc_auth_alloc_active_cfg_list(phba); + if (rc) + return rc; + + pcfg = lpfc_auth_get_active_cfg_ptr(phba); + + pcfg->hdr.signature = cpu_to_le32(0x61757468); + pcfg->hdr.version = 0; + pcfg->hdr.size = sizeof(struct lpfc_auth_cfg_hdr); + pcfg->hdr.entry_cnt = 0; + } + + entry = lpfc_auth_find_cfg_item(phba, &pbuf->lwwpn[0], + &pbuf->rwwpn[0], &valid); + if (!entry) { + pcfg = lpfc_auth_get_active_cfg_ptr(phba); + if (pcfg->hdr.entry_cnt == MAX_AUTH_CONFIG_ENTRIES) + return LPFC_BSG_AUTH_STS_OUT_OF_RESOURCES; + + /* Do not allow matching local and remote passwords */ + if (!memcmp(&pbuf->local.pwd[0], &pbuf->remote.pwd[0], + LPFC_AUTH_PSSWD_MAX_LEN)) + return LPFC_BSG_AUTH_STS_PSSWDS_SAME; + + if (pcfg->hdr.entry_cnt < AUTH_CONFIG_ENTRIES_PER_PAGE) { + entry = &pcfg->entry[pcfg->hdr.entry_cnt]; + } else { + entry = lpfc_auth_get_active_cfg_p2(phba); + entry += pcfg->hdr.entry_cnt - + AUTH_CONFIG_ENTRIES_PER_PAGE; + } + memcpy(&entry->local_wwn[0], &pbuf->lwwpn[0], 8); + memcpy(&entry->remote_wwn[0], &pbuf->rwwpn[0], 8); + pcfg->hdr.entry_cnt++; + } + + if (entry) { + /* Do not allow matching passwords */ + if (pbuf->local.type && pbuf->local.type < 3) { + if (pbuf->remote.type && pbuf->remote.type < 3) { + if (!memcmp(&pbuf->local.pwd[0], + &pbuf->remote.pwd[0], + LPFC_AUTH_PSSWD_MAX_LEN)) + return LPFC_BSG_AUTH_STS_PSSWDS_SAME; + } else { + if (!memcmp(&pbuf->local.pwd[0], + &entry->pwd.remote_pw[0], + LPFC_AUTH_PSSWD_MAX_LEN)) + return LPFC_BSG_AUTH_STS_PSSWDS_SAME; + } + } else + if (pbuf->remote.type && pbuf->remote.type < 3) { + if (!memcmp(&pbuf->remote.pwd[0], + &entry->pwd.local_pw[0], + LPFC_AUTH_PSSWD_MAX_LEN)) + return LPFC_BSG_AUTH_STS_PSSWDS_SAME; + } + /* Authentication with the fabric may be active. */ + ndlp = lpfc_auth_findnode(vport, + (struct lpfc_name *)pbuf->lwwpn, + (struct lpfc_name *)pbuf->rwwpn); + /* Check if authentication is in progress. */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->dhc_cfg.msg == LPFC_AUTH_NEGOTIATE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_CHALLENGE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_REPLY)) + return LPFC_BSG_AUTH_STS_IN_PROGRESS; + + if (pbuf->local.type && pbuf->local.type < 3) { + entry->pwd.local_pw_length = + (uint8_t)pbuf->local.length; + entry->pwd.local_pw_mode = + (uint8_t)pbuf->local.type; + memcpy(&entry->pwd.local_pw[0], + &pbuf->local.pwd[0], + LPFC_AUTH_PSSWD_MAX_LEN); + } + if (pbuf->remote.type && pbuf->remote.type < 3) { + entry->pwd.remote_pw_length = + (uint8_t)pbuf->remote.length; + entry->pwd.remote_pw_mode = + (uint8_t)pbuf->remote.type; + memcpy(&entry->pwd.remote_pw[0], + &pbuf->remote.pwd[0], + LPFC_AUTH_PSSWD_MAX_LEN); + } + + /* if ndlp found, refresh auth cfg */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + ndlp->dhc_cfg.local_passwd_len = + entry->pwd.local_pw_length; + ndlp->dhc_cfg.remote_passwd_len = + entry->pwd.remote_pw_length; + memcpy(ndlp->dhc_cfg.local_passwd, + &entry->pwd.local_pw, + entry->pwd.local_pw_length); + memcpy(ndlp->dhc_cfg.remote_passwd, + &entry->pwd.remote_pw, + entry->pwd.remote_pw_length); + } + } + return rc; +} + +/** + * lpfc_manage_auth_drvr_cfg_update - Update configuration information. + * @phba: Pointer to HBA context object. + * @buf - Pointer to a list of configuration descriptors. + * + * This function updates configuration information, for one or more lwwpn/rwwpn + * pairs described in the list of configuration items provided. + **/ +static int +lpfc_manage_auth_drvr_cfg_update(struct lpfc_vport *vport, uint8_t *buf) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_bsg_auth_cfg_list *clist; + struct lpfc_bsg_auth_cfg_item *ci; + struct lpfc_auth_cfg_entry *entry = NULL; + uint8_t i, item_cnt, valid; + struct lpfc_nodelist *ndlp = NULL; + uint8_t wwpn[8]; + int rc = LPFC_BSG_AUTH_STS_SUCCESS; + + u64_to_wwn(AUTH_FABRIC_WWN, wwpn); + clist = (struct lpfc_bsg_auth_cfg_list *)buf; + if (!clist) + return LPFC_BSG_AUTH_STS_GENERAL_ERROR; + + item_cnt = clist->entry_cnt; + for (i = 0; i < item_cnt; i++) { + entry = lpfc_auth_find_cfg_item(phba, + &clist->cfg_item[i].lwwpn[0], + &clist->cfg_item[i].rwwpn[0], + &valid); + if (entry) { + ci = &clist->cfg_item[i]; + if ((entry->pwd.local_pw_length == 0) || + (entry->pwd.local_pw_mode == 0) || + (entry->pwd.local_pw_mode > 2) || + (entry->pwd.local_pw[0] == 0)) { + ci->status = + LPFC_BSG_AUTH_STS_LOCAL_SECRET_NOT_SET; + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + continue; + } + + /* Authentication with the fabric may be active. */ + ndlp = lpfc_auth_findnode(vport, + (struct lpfc_name *)ci->lwwpn, + (struct lpfc_name *)ci->rwwpn + ); + /* Check if authentication is in progress. */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->dhc_cfg.msg == LPFC_AUTH_NEGOTIATE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_CHALLENGE || + ndlp->dhc_cfg.msg == LPFC_DHCHAP_REPLY)) { + ci->status = + LPFC_BSG_AUTH_STS_IN_PROGRESS; + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + continue; + } + + /* update existing entry */ + memcpy(entry, ci->lwwpn, + sizeof(struct lpfc_auth_cfg_entry) - + sizeof(struct lpfc_auth_pwd_entry)); + + if (ci->reauth_interval > REAUTH_MAX_INTERVAL) + entry->reauth_interval = REAUTH_MAX_INTERVAL; + + entry->auth_flags.valid = 1; + ci->status = 0; + + /* if ndlp found, refresh auth cfg */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + ndlp->dhc_cfg.auth_tmo = entry->auth_tmo; + ndlp->dhc_cfg.auth_mode = entry->auth_mode; + ndlp->dhc_cfg.bidirectional = + entry->auth_flags.bi_direction; + ndlp->dhc_cfg.reauth_interval = + entry->reauth_interval; + ndlp->dhc_cfg.direction = AUTH_DIRECTION_NONE; + + /* [re]start re-authentication */ + if (ndlp->dhc_cfg.reauth_interval && + ndlp->dhc_cfg.state == LPFC_AUTH_SUCCESS) + lpfc_auth_start_reauth_tmr(ndlp); + } + } else { + clist->cfg_item[i].status = + LPFC_BSG_AUTH_STS_LOCAL_SECRET_NOT_SET; + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + } + } + return rc; +} + +/** + * lpfc_manage_auth_cfg_fetch - Return configuration information. + * @phba: Pointer to HBA context object. + * @buf - Pointer to a list of configuration descriptors. + * @src - Argument specifying the configuration information source. + * 0 - active (driver) configuration. + * 1 - saved (flash) configuration. + * + * This function returns configuration information, if available, for one or + * more configuration entries matching the wwpn pairs described in the list. + * The src parameter specifies whether the saved or active configuration + * values are to be used. + **/ +static int +lpfc_manage_auth_cfg_fetch(struct lpfc_hba *phba, uint8_t *buf, + uint8_t *wwpn, uint8_t src) +{ + struct lpfc_bsg_auth_cfg_list *clist; + struct lpfc_bsg_auth_cfg_item *cfg_item; + uint8_t wwn_match[8]; + struct list_head dmabuf_list; + struct lpfc_dmabuf *dmabuf, *next; + struct lpfc_auth_cfg *pcfg = NULL; + struct lpfc_auth_cfg_entry *ptmp_p2 = NULL; + struct lpfc_auth_cfg_entry *entry = NULL; + uint32_t offset; + uint8_t i, j, item_cnt; + char *obj_name = {"/driver/auth.cfg"}; + int rc = 0; + + if (src) { + /* use the saved configuration */ + INIT_LIST_HEAD(&dmabuf_list); + for (i = 0; i < 2; i++) { + dmabuf = kzalloc(sizeof(*dmabuf), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + SLI4_PAGE_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + rc = -ENOMEM; + goto release_out; + } + if (i) + ptmp_p2 = (struct lpfc_auth_cfg_entry *) + dmabuf->virt; + else + pcfg = (struct lpfc_auth_cfg *)dmabuf->virt; + + list_add_tail(&dmabuf->list, &dmabuf_list); + } + + offset = phba->sli4_hba.lnk_info.lnk_no * SLI4_PAGE_SIZE * 2; + rc = lpfc_auth_rd_object(phba, &dmabuf_list, + SLI4_PAGE_SIZE * 2, &offset, + obj_name); + if (rc || offset < sizeof(struct lpfc_auth_cfg_hdr)) { + rc = LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; + goto release_out; + } + + } else { + /* use active configuration */ + pcfg = lpfc_auth_get_active_cfg_ptr(phba); + if (!pcfg) + return LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; + + ptmp_p2 = lpfc_auth_get_active_cfg_p2(phba); + } + + clist = (struct lpfc_bsg_auth_cfg_list *)buf; + if (!clist) { + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + goto release_out; + } + u64_to_wwn(AUTH_FABRIC_WWN, wwn_match); + item_cnt = clist->entry_cnt; + if (!item_cnt) { + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + goto release_out; + } + + if (!pcfg->hdr.entry_cnt) + return LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; + + if (item_cnt > MAX_AUTH_CONFIG_ENTRIES) + item_cnt = MAX_AUTH_CONFIG_ENTRIES; + + entry = &pcfg->entry[0]; + cfg_item = &clist->cfg_item[0]; /* only used for exact match search */ + for (i = 0, j = 0; i < pcfg->hdr.entry_cnt; i++, entry++) { + if (i == AUTH_CONFIG_ENTRIES_PER_PAGE) + entry = ptmp_p2; /* switching to second page */ + + if (memcmp(wwpn, &wwn_match, 8)) { /* match specified */ + if (*(uint64_t *)wwpn == 0) { /* match exact */ + if ((memcmp(&entry->local_wwn, + &cfg_item->lwwpn, 8)) || + (memcmp(&entry->remote_wwn, + &cfg_item->rwwpn, 8))) + continue; + } else if (memcmp(wwpn, &entry->local_wwn, 8)) { + continue; + } + } + if (j < item_cnt) { + memcpy(&clist->cfg_item[j], entry, + sizeof(struct lpfc_bsg_auth_cfg_item)); + /* check for a config */ + if (entry->auth_flags.valid) + clist->cfg_item[j].status = 0; + else { + clist->cfg_item[j].status = + LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + rc = LPFC_BSG_AUTH_STS_NOT_CONFIGURED; + } + } + j++; + } + clist->entry_cnt = j; + if (clist->entry_cnt > item_cnt) + rc = LPFC_BSG_AUTH_STS_MORE_DATA_AVAILABLE; + else if (!rc && !clist->entry_cnt) + rc = LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; +release_out: + if (src) + list_for_each_entry_safe(dmabuf, next, &dmabuf_list, list) { + list_del(&dmabuf->list); + dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + + return rc; +} + +/** + * lpfc_manage_auth_cfg_delete - remove configuration information. + * @phba: Pointer to HBA context object. + * @buf - Pointer to a list of configuration descriptors. + * @flag - argument to specify scope of the wwpn matching. + * + * This function deletes configuration information for one or more lwwpn/rwwpn + * pairs described in the list of configuration items provided. + **/ +static int +lpfc_manage_auth_cfg_delete(struct lpfc_vport *vport, uint8_t *buf, + uint8_t flag) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_bsg_auth_cfg_list *plist; + struct lpfc_bsg_auth_cfg_item *cfg_item; + struct lpfc_auth_cfg *d_cfg = NULL; + struct lpfc_auth_cfg_entry *d_item, *d_last; + struct lpfc_nodelist *ndlp = NULL; + uint8_t i, j, item_cnt_p, item_cnt_d, *p2; + int rc = 0; + + plist = (struct lpfc_bsg_auth_cfg_list *)buf; + if (plist) + item_cnt_p = plist->entry_cnt; + + d_cfg = lpfc_auth_get_active_cfg_ptr(phba); + if (!d_cfg) { + /* no driver config found. */ + if (plist) { + for (i = 0; i < item_cnt_p; i++) + plist->cfg_item[i].status = + LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; + } + return LPFC_BSG_AUTH_STS_GENERAL_ERROR; + } + + if (flag == 1) { + /* delete all entries */ + memset(&d_cfg->entry[0], 0, + SLI4_PAGE_SIZE - sizeof(struct lpfc_auth_cfg_hdr)); + + if (d_cfg->hdr.entry_cnt > AUTH_CONFIG_ENTRIES_PER_PAGE) { + p2 = (uint8_t *)lpfc_auth_get_active_cfg_p2(phba); + if (p2) + memset(p2, 0, SLI4_PAGE_SIZE); + } + d_cfg->hdr.entry_cnt = 0; + return rc; + } + + if (!plist) + return LPFC_BSG_AUTH_STS_GENERAL_ERROR; + + item_cnt_d = d_cfg->hdr.entry_cnt; + if (item_cnt_d > MAX_AUTH_CONFIG_ENTRIES) + item_cnt_d = MAX_AUTH_CONFIG_ENTRIES; + + /* delete items described in list */ + for (i = 0; i < item_cnt_p; i++) { + cfg_item = &plist->cfg_item[i]; + cfg_item->status = LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND; + + if (d_cfg->hdr.entry_cnt == 0) { + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + continue; + } + d_item = &d_cfg->entry[0]; + if (d_cfg->hdr.entry_cnt < AUTH_CONFIG_ENTRIES_PER_PAGE) { + d_last = &d_cfg->entry[d_cfg->hdr.entry_cnt - 1]; + } else { + d_last = lpfc_auth_get_active_cfg_p2(phba); + d_last += d_cfg->hdr.entry_cnt - + AUTH_CONFIG_ENTRIES_PER_PAGE; + } + + for (j = 0; j < d_cfg->hdr.entry_cnt; j++) { + if (j == AUTH_CONFIG_ENTRIES_PER_PAGE) + d_item = (struct lpfc_auth_cfg_entry *) + lpfc_auth_get_active_cfg_p2(phba); + + if ((memcmp(&d_item->local_wwn[0], + &cfg_item->lwwpn[0], 8) == 0) && + (memcmp(&d_item->remote_wwn[0], + &cfg_item->rwwpn[0], 8) == 0)) { + /* match found */ + ndlp = lpfc_auth_findnode(vport, + (struct lpfc_name *) + d_item->local_wwn, + (struct lpfc_name *) + d_item->remote_wwn); + + /* check for authentication active */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->dhc_cfg.msg == + LPFC_AUTH_NEGOTIATE || + ndlp->dhc_cfg.msg == + LPFC_DHCHAP_CHALLENGE || + ndlp->dhc_cfg.msg == + LPFC_DHCHAP_REPLY)) { + cfg_item->status = + LPFC_BSG_AUTH_STS_IN_PROGRESS; + rc = LPFC_BSG_AUTH_STS_GENERAL_ERROR; + continue; + } + + if (d_last != d_item) + memcpy(d_item, d_last, + sizeof(struct + lpfc_auth_cfg_entry)); + + memset(d_last, 0, + sizeof(struct lpfc_auth_cfg_entry)); + d_cfg->hdr.entry_cnt--; + cfg_item->status = 0; /* success */ + break; + } + d_item++; + } + } + return rc; +} + +/** + * lpfc_manage_auth_cfg - Provides processing of various auth cfg changes. + * @job: fc_bsg_job to handle + * + * This function updates configuration information described in the job. + **/ +static int +lpfc_manage_auth_cfg(struct bsg_job *job) + +{ + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct auth_cfg_mgmt_req *auth_req; + uint32_t xfr_size; + uint8_t *xfr_data = NULL; + int rc = 0; + + /* in case no data transferred */ + bsg_reply->reply_payload_rcv_len = 0; + + if (job->request_len < (sizeof(struct fc_bsg_request) + + sizeof(struct auth_cfg_mgmt_req))) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3149 Received AUTH_MGMT request below " + "minimum size\n"); + rc = -EINVAL; + goto update_auth_cfg_exit; + } + auth_req = (struct auth_cfg_mgmt_req *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + + if (!auth_req) { + rc = -EINVAL; + goto update_auth_cfg_exit; + } + + xfr_size = job->request_payload.payload_len; + if (xfr_size) { + if (xfr_size > BUF_SZ_4K) + xfr_size = BUF_SZ_4K; + xfr_data = kmalloc(xfr_size, GFP_KERNEL); + if (!xfr_data) { + rc = -ENOMEM; + goto update_auth_cfg_exit; + } + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + xfr_data, xfr_size); + } + + switch (auth_req->cfg_op) { + case AUTH_MGMT_OP_GET_CFG: + rc = lpfc_manage_auth_cfg_fetch(phba, xfr_data, + auth_req->wwpn, + (uint8_t)auth_req->param); + break; + case AUTH_MGMT_OP_SET_CFG: + rc = lpfc_manage_auth_drvr_cfg_update(vport, xfr_data); + break; + case AUTH_MGMT_OP_DEL_CFG: + rc = lpfc_manage_auth_cfg_delete(vport, xfr_data, + (uint8_t)auth_req->param); + break; + case AUTH_MGMT_OP_SET_PWD: + rc = lpfc_manage_auth_pwd_update(vport, xfr_data); + break; + case AUTH_MGMT_OP_GET_PWD: + rc = lpfc_manage_auth_pwd_fetch(phba, xfr_data, + (uint8_t)auth_req->param); + break; + case AUTH_MGMT_OP_DEL_OBJ: + rc = lpfc_del_object(phba, xfr_data); + break; + case AUTH_MGMT_OP_RMW_OBJ: + rc = lpfc_manage_auth_update_obj(phba, xfr_data); + break; + default: + rc = -EINVAL; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC | LOG_AUTH, + "3171 Unknown auth mgmt cmd:%x op:%x " + "wwpn: %llx flags x%x\n", + auth_req->command, auth_req->cfg_op, + *(uint64_t *)&auth_req->wwpn, auth_req->param); + break; + } + + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + xfr_data, xfr_size); + + kfree(xfr_data); +update_auth_cfg_exit: + bsg_reply->result = rc; + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + return rc; +} +#endif + /** * lpfc_check_fwlog_support: Check FW log support on the adapter * @phba: Pointer to HBA context object. @@ -5438,10 +6827,12 @@ lpfc_bsg_get_ras_config(struct bsg_job *job) bsg_reply->reply_data.vendor_reply.vendor_rsp; /* Current logging state */ - if (ras_fwlog->ras_active == true) + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state == ACTIVE) ras_reply->state = LPFC_RASLOG_STATE_RUNNING; else ras_reply->state = LPFC_RASLOG_STATE_STOPPED; + spin_unlock_irq(&phba->hbalock); ras_reply->log_level = phba->ras_fwlog.fw_loglevel; ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize; @@ -5498,10 +6889,13 @@ lpfc_bsg_set_ras_config(struct bsg_job *job) if (action == LPFC_RASACTION_STOP_LOGGING) { /* Check if already disabled */ - if (ras_fwlog->ras_active == false) { + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); rc = -ESRCH; goto ras_job_error; } + spin_unlock_irq(&phba->hbalock); /* Disable logging */ lpfc_ras_stop_fwlog(phba); @@ -5512,8 +6906,10 @@ lpfc_bsg_set_ras_config(struct bsg_job *job) * FW-logging with new log-level. Return status * "Logging already Running" to caller. **/ - if (ras_fwlog->ras_active) + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state != INACTIVE) action_status = -EINPROGRESS; + spin_unlock_irq(&phba->hbalock); /* Enable logging */ rc = lpfc_sli4_ras_fwlog_init(phba, log_level, @@ -5629,10 +7025,13 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job) goto ras_job_error; /* Logging to be stopped before reading */ - if (ras_fwlog->ras_active == true) { + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state == ACTIVE) { + spin_unlock_irq(&phba->hbalock); rc = -EINPROGRESS; goto ras_job_error; } + spin_unlock_irq(&phba->hbalock); if (job->request_len < sizeof(struct fc_bsg_request) + @@ -5706,8 +7105,7 @@ lpfc_get_trunk_info(struct bsg_job *job) event_reply = (struct lpfc_trunk_info *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct lpfc_trunk_info)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2728 Received GET TRUNK _INFO reply below " "minimum size\n"); @@ -5758,6 +7156,92 @@ job_error: } +static int +lpfc_get_cgnbuf_info(struct bsg_job *job) +{ + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct get_cgnbuf_info_req *cgnbuf_req; + struct lpfc_cgn_info *cp; + uint8_t *cgn_buff; + int size, cinfosz; + int rc = 0; + + if (job->request_len < sizeof(struct fc_bsg_request) + + sizeof(struct get_cgnbuf_info_req)) { + rc = -ENOMEM; + goto job_exit; + } + + if (!phba->sli4_hba.pc_sli4_params.cmf) { + rc = -ENOENT; + goto job_exit; + } + + if (!phba->cgn_i || !phba->cgn_i->virt) { + rc = -ENOENT; + goto job_exit; + } + + cp = phba->cgn_i->virt; + if (cp->cgn_info_version < LPFC_CGN_INFO_V3) { + rc = -EPERM; + goto job_exit; + } + + cgnbuf_req = (struct get_cgnbuf_info_req *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + + /* For reset or size == 0 */ + bsg_reply->reply_payload_rcv_len = 0; + + if (cgnbuf_req->reset == LPFC_BSG_CGN_RESET_STAT) { + lpfc_init_congestion_stat(phba); + goto job_exit; + } + + /* We don't want to include the CRC at the end */ + cinfosz = sizeof(struct lpfc_cgn_info) - sizeof(uint32_t); + + size = cgnbuf_req->read_size; + if (!size) + goto job_exit; + + if (size < cinfosz) { + /* Just copy back what we can */ + cinfosz = size; + rc = -E2BIG; + } + + /* Allocate memory to read congestion info */ + cgn_buff = vmalloc(cinfosz); + if (!cgn_buff) { + rc = -ENOMEM; + goto job_exit; + } + + memcpy(cgn_buff, cp, cinfosz); + + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + cgn_buff, cinfosz); + + vfree(cgn_buff); + +job_exit: + bsg_reply->result = rc; + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + else + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "2724 GET CGNBUF error: %d\n", rc); + return rc; +} + /** * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * @job: fc_bsg_job to handle @@ -5802,9 +7286,22 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) case LPFC_BSG_VENDOR_MENLO_DATA: rc = lpfc_menlo_cmd(job); break; +#ifndef NO_APEX + case LPFC_BSG_VENDOR_SET_FCP_PRIORITY: + rc = lpfc_bsg_set_fcp_priority(job); + break; + case LPFC_BSG_VENDOR_GET_FCP_PRIORITY: + rc = lpfc_bsg_get_fcp_priority(job); + break; +#endif case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: rc = lpfc_forced_link_speed(job); break; +#ifndef BUILD_BRCMFCOE + case LPFC_BSG_VENDOR_AUTH_CFG_MGMT: + rc = lpfc_manage_auth_cfg(job); + break; +#endif case LPFC_BSG_VENDOR_RAS_GET_LWPD: rc = lpfc_bsg_get_ras_lwpd(job); break; @@ -5820,6 +7317,9 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) case LPFC_BSG_VENDOR_GET_TRUNK_INFO: rc = lpfc_get_trunk_info(job); break; + case LPFC_BSG_VENDOR_GET_CGNBUF_INFO: + rc = lpfc_get_cgnbuf_info(job); + break; default: rc = -EINVAL; bsg_reply->reply_payload_rcv_len = 0; @@ -5987,3 +7487,4 @@ lpfc_bsg_timeout(struct bsg_job *job) */ return rc; } + diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index d1708133f..af6bd925e 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2010-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -37,12 +37,18 @@ #define LPFC_BSG_VENDOR_MENLO_DATA 9 #define LPFC_BSG_VENDOR_DIAG_MODE_END 10 #define LPFC_BSG_VENDOR_LINK_DIAG_TEST 11 +#ifndef NO_APEX +#define LPFC_BSG_VENDOR_GET_FCP_PRIORITY 12 +#define LPFC_BSG_VENDOR_SET_FCP_PRIORITY 13 +#endif #define LPFC_BSG_VENDOR_FORCED_LINK_SPEED 14 +#define LPFC_BSG_VENDOR_AUTH_CFG_MGMT 15 #define LPFC_BSG_VENDOR_RAS_GET_LWPD 16 #define LPFC_BSG_VENDOR_RAS_GET_FWLOG 17 #define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18 #define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19 #define LPFC_BSG_VENDOR_GET_TRUNK_INFO 20 +#define LPFC_BSG_VENDOR_GET_CGNBUF_INFO 21 struct set_ct_event { uint32_t command; @@ -105,8 +111,13 @@ struct get_mgmt_rev { uint32_t command; }; +#ifndef NO_APEX +#define MANAGEMENT_MAJOR_REV 2 +#define MANAGEMENT_MINOR_REV 0 +#else #define MANAGEMENT_MAJOR_REV 1 #define MANAGEMENT_MINOR_REV 1 +#endif /* the MgmtRevInfo structure */ struct MgmtRevInfo { @@ -225,6 +236,10 @@ struct lpfc_sli_config_hdr { uint32_t reserved5; }; +#define LPFC_CSF_BOOT_DEV 0x1D +#define LPFC_CSF_QUERY 0 +#define LPFC_CSF_SAVE 1 + struct lpfc_sli_config_emb0_subsys { struct lpfc_sli_config_hdr sli_config_hdr; #define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 @@ -243,6 +258,15 @@ struct lpfc_sli_config_emb0_subsys { #define FCOE_OPCODE_ADD_FCF 0x09 #define FCOE_OPCODE_SET_DPORT_MODE 0x27 #define FCOE_OPCODE_GET_DPORT_RESULTS 0x28 + uint32_t timeout; /* comn_set_feature timeout */ + uint32_t request_length; /* comn_set_feature request len */ + uint32_t version; /* comn_set_feature version */ + uint32_t csf_feature; /* comn_set_feature feature */ + uint32_t word69; /* comn_set_feature parameter len */ + uint32_t word70; /* comn_set_feature parameter val0 */ +#define lpfc_emb0_subcmnd_csf_p0_SHIFT 0 +#define lpfc_emb0_subcmnd_csf_p0_MASK 0x3 +#define lpfc_emb0_subcmnd_csf_p0_WORD word70 }; struct lpfc_sli_config_emb1_subsys { @@ -261,6 +285,7 @@ struct lpfc_sli_config_emb1_subsys { #define COMN_OPCODE_WRITE_OBJECT 0xAC #define COMN_OPCODE_READ_OBJECT_LIST 0xAD #define COMN_OPCODE_DELETE_OBJECT 0xAE +#define COMN_OPCODE_SET_FEATURES 0xBF #define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 #define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20 uint32_t timeout; @@ -294,6 +319,40 @@ struct lpfc_sli_config_mbox { } un; }; +#ifndef NO_APEX +struct lpfc_fcp_pri_rule { + uint8_t src_wwpn[8]; + uint8_t tgt_wwpn[8]; + uint8_t first_lun[8]; + uint8_t last_lun[8]; + uint8_t fcp_priority; + uint8_t rsvrd[3]; +}; + +struct lpfc_fcp_pri_rules { + uint32_t number_of_entries; /* Number of rules in the array */ + struct lpfc_fcp_pri_rule rule_entry[0]; +}; + +struct get_lpfc_fcp_pri_rules { + uint32_t command; + uint32_t number_of_entries; /* number of rules to return */ +}; + +struct get_lpfc_fcp_pri_rules_reply { + struct lpfc_fcp_pri_rules rule; +}; + +struct set_lpfc_fcp_pri_rules { + uint32_t command; + uint32_t number_of_entries; /* number of rules passed to driver */ +}; +/* limits for fcp priority rules */ +#define LPFC_MAX_FCP_RULES 999 /* number of rules */ +/* so we can add 1 more than the get */ +#define LPFC_MAX_FCP_SET_RULES (LPFC_MAX_FCP_RULES + 1) +#endif + #define LPFC_FORCED_LINK_SPEED_NOT_SUPPORTED 0 #define LPFC_FORCED_LINK_SPEED_SUPPORTED 1 struct get_forced_link_speed_support { @@ -303,6 +362,73 @@ struct forced_link_speed_support_reply { uint8_t supported; }; +struct lpfc_bsg_auth_cfg_item { + uint8_t lwwpn[8]; + uint8_t rwwpn[8]; + uint16_t auth_tmo; + uint8_t auth_mode; + struct { + uint8_t bi_direction : 1; + uint8_t rsvd : 6; + uint8_t valid : 1; + } auth_flags; + uint8_t auth_priority[4]; + uint8_t hash_priority[4]; + uint8_t dh_grp_priority[8]; + uint32_t reauth_interval; +#define REAUTH_MAX_INTERVAL 3600 /* minutes */ + uint32_t status; + uint32_t rsvd; +}; + +struct lpfc_bsg_auth_cfg_list { + uint32_t version; + uint32_t entry_cnt; + uint32_t rsvd; + struct lpfc_bsg_auth_cfg_item cfg_item[0]; +}; + +#define AUTH_MGMT_OP_SET_CFG 1 +#define AUTH_MGMT_OP_GET_CFG 2 +#define AUTH_MGMT_OP_DEL_CFG 3 +#define AUTH_MGMT_OP_SET_PWD 4 +#define AUTH_MGMT_OP_GET_PWD 5 +#define AUTH_MGMT_OP_RMW_OBJ 6 +#define AUTH_MGMT_OP_DEL_OBJ 7 + +struct auth_cfg_mgmt_req { + uint32_t command; + uint32_t cfg_op; + uint8_t wwpn[8]; + uint32_t param; +}; + +struct lpfc_bsg_auth_pwd_info { + uint16_t length; + uint16_t type; + uint8_t pwd[128]; +}; + +struct lpfc_bsg_auth_pwd_item { + uint8_t lwwpn[8]; + uint8_t rwwpn[8]; + struct lpfc_bsg_auth_pwd_info local; + struct lpfc_bsg_auth_pwd_info remote; +}; + +#define LPFC_BSG_AUTH_STS_SUCCESS 0x0000 +#define LPFC_BSG_AUTH_STS_NOT_CONFIGURED 0x8001 +#define LPFC_BSG_AUTH_STS_MORE_DATA_AVAILABLE 0x8007 +#define LPFC_BSG_AUTH_STS_INVALID_OPERATION 0x8009 +#define LPFC_BSG_AUTH_STS_OUT_OF_RESOURCES 0x800a +#define LPFC_BSG_AUTH_STS_IN_PROGRESS 0x800b +#define LPFC_BSG_AUTH_STS_PSSWDS_SAME 0x8011 +#define LPFC_BSG_AUTH_STS_DRVTYPE_NOT_SUPPORTED 0x8030 +#define LPFC_BSG_AUTH_STS_AUTHENTICATION_NOT_SUPPORTED 0x8031 +#define LPFC_BSG_AUTH_STS_GENERAL_ERROR 0x8032 +#define LPFC_BSG_AUTH_STS_CONFIG_NOT_FOUND 0x8034 +#define LPFC_BSG_AUTH_STS_LOCAL_SECRET_NOT_SET 0x8050 + struct lpfc_bsg_ras_req { uint32_t command; }; @@ -372,6 +498,13 @@ struct get_trunk_info_req { uint32_t command; }; +struct get_cgnbuf_info_req { + uint32_t command; + uint32_t read_size; + uint32_t reset; +#define LPFC_BSG_CGN_RESET_STAT 1 +}; + /* driver only */ #define SLI_CONFIG_NOT_HANDLED 0 #define SLI_CONFIG_HANDLED 1 diff --git a/drivers/scsi/lpfc/lpfc_compat.h b/drivers/scsi/lpfc/lpfc_compat.h index 43cf46a3a..ef128fea4 100644 --- a/drivers/scsi/lpfc/lpfc_compat.h +++ b/drivers/scsi/lpfc/lpfc_compat.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bdb1f380e..564474b63 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *); struct fc_rport; +bool lpfc_throttler(struct lpfc_vport *, struct throttle_history *); struct fc_frame_header; struct lpfc_nvmet_rcv_ctx; void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -56,9 +57,14 @@ void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); +void lpfc_supported_pages(struct lpfcMboxq *); +void lpfc_pc_sli4_params(struct lpfcMboxq *); +int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *, uint16_t, uint16_t, bool); int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_reg_congestion_buf(struct lpfc_hba *); +int lpfc_unreg_congestion_buf(struct lpfc_hba *phba); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); @@ -75,6 +81,20 @@ int lpfc_init_iocb_list(struct lpfc_hba *phba, int cnt); void lpfc_free_iocb_list(struct lpfc_hba *phba); int lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct lpfc_queue *drq, int count, int idx); +uint32_t lpfc_calc_cmf_latency(struct lpfc_hba *phba); +void lpfc_cmf_signal_init(struct lpfc_hba *phba); +void lpfc_cmf_start(struct lpfc_hba *phba); +void lpfc_cmf_stop(struct lpfc_hba *phba); +void lpfc_init_congestion_stat(struct lpfc_hba *phba); +void lpfc_init_congestion_buf(struct lpfc_hba *phba); +int lpfc_sli4_cgn_params_read(struct lpfc_hba *); +uint32_t lpfc_cgn_calc_crc32(void *, uint32_t, uint32_t); +int lpfc_config_cgn_signal(struct lpfc_hba *); +int lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total); +void lpfc_cgn_dump_rxmonitor(struct lpfc_hba *phba); +void lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag); +void lpfc_unblock_requests(struct lpfc_hba *); +void lpfc_block_requests(struct lpfc_hba *); void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -103,13 +123,50 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_nodelist *lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did); struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); int lpfc_nlp_put(struct lpfc_nodelist *); +void lpfc_els_rcv_fpin(struct lpfc_vport *vport, void *p, u32 len); int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp); struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *); void lpfc_cleanup_discovery_resources(struct lpfc_vport *); void lpfc_cleanup(struct lpfc_vport *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_disc_timeout(unsigned long); +#else void lpfc_disc_timeout(struct timer_list *); +#endif +#ifndef BUILD_BRCMFCOE +struct lpfc_nodelist * +lpfc_auth_findnode(struct lpfc_vport *, struct lpfc_name *, struct lpfc_name *); +int lpfc_auth_alloc_active_cfg_list(struct lpfc_hba *); +void lpfc_auth_free_active_cfg_list(struct lpfc_hba *); +int lpfc_auth_read_cfg_object(struct lpfc_hba *); +int lpfc_auth_issue_rd_object(struct lpfc_hba *, struct list_head *, + uint32_t, uint32_t *, char *); +void lpfc_auth_cmpl_rd_object(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_del_object(struct lpfc_hba *, char *); +int lpfc_auth_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, + uint32_t *, char *); +int lpfc_auth_rd_object(struct lpfc_hba *, struct list_head *, uint32_t, + uint32_t *, char *); +struct lpfc_auth_cfg *lpfc_auth_get_active_cfg_ptr(struct lpfc_hba *phba); +struct lpfc_auth_cfg_entry *lpfc_auth_get_active_cfg_p2(struct lpfc_hba *phba); +struct lpfc_auth_cfg_entry *lpfc_auth_find_cfg_item(struct lpfc_hba *phba, + uint8_t *lwwpn, + uint8_t *rwwpn, + uint8_t *valid); +int lpfc_auth_start(struct lpfc_vport *, struct lpfc_nodelist *); +void lpfc_auth_start_reauth_tmr(struct lpfc_nodelist *ndlp); +int lpfc_auth_handle_cmd(struct lpfc_vport *, struct lpfc_iocbq *, + struct lpfc_nodelist *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_auth_reauth(unsigned long ptr); +#else +void lpfc_auth_reauth(struct timer_list *); +#endif +void lpfc_auth_timeout_handler(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); +#endif int lpfc_unregister_fcf_prep(struct lpfc_hba *); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); @@ -137,9 +194,11 @@ int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); -int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); -int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); +int lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry); +int lpfc_issue_els_rscn(struct lpfc_vport *, uint8_t); int lpfc_issue_fabric_reglogin(struct lpfc_vport *); +int lpfc_issue_els_rdf(struct lpfc_vport *, uint8_t); +int lpfc_issue_els_edc(struct lpfc_vport *phba, uint8_t retry); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, @@ -151,7 +210,11 @@ int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *, int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *, struct lpfc_nodelist *); void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_els_retry_delay(unsigned long); +#else void lpfc_els_retry_delay(struct timer_list *); +#endif void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); @@ -162,7 +225,11 @@ void lpfc_els_flush_all_cmd(struct lpfc_hba *); void lpfc_els_flush_cmd(struct lpfc_vport *); int lpfc_els_disc_adisc(struct lpfc_vport *); int lpfc_els_disc_plogi(struct lpfc_vport *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_els_timeout(unsigned long); +#else void lpfc_els_timeout(struct timer_list *); +#endif void lpfc_els_timeout_handler(struct lpfc_vport *); struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, uint8_t, struct lpfc_nodelist *, @@ -172,13 +239,17 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *); -int lpfc_issue_gidpt(struct lpfc_vport *vport); -int lpfc_issue_gidft(struct lpfc_vport *vport); +uint32_t lpfc_issue_gidpt(struct lpfc_vport *vport); +uint32_t lpfc_issue_gidft(struct lpfc_vport *vport); int lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *iocbq); int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t); void lpfc_fdmi_change_check(struct lpfc_vport *vport); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_delayed_disc_tmo(unsigned long); +#else void lpfc_delayed_disc_tmo(struct timer_list *); +#endif void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *); int lpfc_config_port_prep(struct lpfc_hba *); @@ -189,6 +260,7 @@ int lpfc_hba_down_post(struct lpfc_hba *); void lpfc_hba_init(struct lpfc_hba *, uint32_t *); int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int); void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); +int lpfc_issue_lip(struct Scsi_Host *); int lpfc_online(struct lpfc_hba *); void lpfc_unblock_mgmt_io(struct lpfc_hba *); void lpfc_offline_prep(struct lpfc_hba *, int); @@ -212,9 +284,16 @@ irqreturn_t lpfc_sli_fp_intr_handler(int, void *); irqreturn_t lpfc_sli4_intr_handler(int, void *); irqreturn_t lpfc_sli4_hba_intr_handler(int, void *); +int lpfc_read_object(struct lpfc_hba *, char *, uint32_t *, uint32_t); +int lpfc_write_object(struct lpfc_hba *, char *, uint32_t *, uint32_t); + void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba); int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_sli4_poll_hbtimer(unsigned long ptr); +#else void lpfc_sli4_poll_hbtimer(struct timer_list *t); +#endif void lpfc_sli4_start_polling(struct lpfc_queue *q); void lpfc_sli4_stop_polling(struct lpfc_queue *q); @@ -254,8 +333,10 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr); void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq); -void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba); -void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba); +void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *); +#if defined(BUILD_NVME) +void lpfc_nvme_issue_pend_io(struct work_struct *work); +#endif void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, uint16_t); int lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, @@ -281,9 +362,17 @@ void lpfc_mem_free(struct lpfc_hba *); void lpfc_mem_free_all(struct lpfc_hba *); void lpfc_stop_vport_timers(struct lpfc_vport *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_poll_timeout(unsigned long ptr); +#else void lpfc_poll_timeout(struct timer_list *t); +#endif void lpfc_poll_start_timer(struct lpfc_hba *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_poll_eratt(unsigned long); +#else void lpfc_poll_eratt(struct timer_list *); +#endif int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); @@ -299,7 +388,7 @@ int lpfc_selective_reset(struct lpfc_hba *); void lpfc_reset_barrier(struct lpfc_hba *); int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); int lpfc_sli_brdkill(struct lpfc_hba *); -int lpfc_sli_chipset_init(struct lpfc_hba *phba); +int lpfc_sli_chipset_init(struct lpfc_hba *); int lpfc_sli_brdreset(struct lpfc_hba *); int lpfc_sli_brdrestart(struct lpfc_hba *); int lpfc_sli_hba_setup(struct lpfc_hba *); @@ -353,13 +442,19 @@ int lpfc_sli_abort_taskmgmt(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, uint64_t, lpfc_ctx_cmd); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_mbox_timeout(unsigned long); +#else void lpfc_mbox_timeout(struct timer_list *t); +#endif void lpfc_mbox_timeout_handler(struct lpfc_hba *); +int lpfc_issue_hb_mbox(struct lpfc_hba *phba); +void lpfc_issue_hb_tmo(struct lpfc_hba *phba); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, struct lpfc_name *); -struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport); +struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *); int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -383,7 +478,7 @@ void lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp); int lpfc_link_reset(struct lpfc_vport *vport); /* Function prototypes. */ -int lpfc_check_pci_resettable(const struct lpfc_hba *phba); +int lpfc_check_pci_resettable(struct lpfc_hba *phba); const char* lpfc_info(struct Scsi_Host *); int lpfc_scan_finished(struct Scsi_Host *, unsigned long); @@ -400,16 +495,14 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); extern struct device_attribute *lpfc_hba_attrs[]; extern struct device_attribute *lpfc_vport_attrs[]; extern struct scsi_host_template lpfc_template; -extern struct scsi_host_template lpfc_template_no_hr; extern struct scsi_host_template lpfc_template_nvme; -extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); void lpfc_terminate_rport_io(struct fc_rport *); -void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); +void lpfc_dev_loss_tmo_callbk(struct fc_rport *); struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *); int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable); @@ -436,10 +529,19 @@ int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t, int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t, uint16_t *, uint16_t *); +extern void lpfc_edsm_validate_target(struct lpfc_vport *, + struct lpfc_nodelist *); +extern void lpfc_edsm_set_state(struct lpfc_vport *, + struct lpfc_external_dif_support *, uint32_t); + /* Interface exported by fabric iocb scheduler */ void lpfc_fabric_abort_nport(struct lpfc_nodelist *); void lpfc_fabric_abort_hba(struct lpfc_hba *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_fabric_block_timeout(unsigned long); +#else void lpfc_fabric_block_timeout(struct timer_list *); +#endif void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); void lpfc_rampdown_queue_depth(struct lpfc_hba *); void lpfc_ramp_down_queue_handler(struct lpfc_hba *); @@ -453,6 +555,9 @@ void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *); void lpfc_create_static_vport(struct lpfc_hba *); void lpfc_stop_hba_timers(struct lpfc_hba *); void lpfc_stop_port(struct lpfc_hba *); +int lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t sz); +int lpfc_update_cmf_cmpl(struct lpfc_hba *phba, uint64_t val, uint32_t sz, + struct Scsi_Host *shost); void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t); @@ -460,6 +565,7 @@ int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); void lpfc_start_fdiscs(struct lpfc_hba *phba); struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t); struct lpfc_sglq *__lpfc_get_active_sglq(struct lpfc_hba *, uint16_t); +#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define HBA_EVENT_RSCN 5 #define HBA_EVENT_LINK_UP 2 #define HBA_EVENT_LINK_DOWN 3 @@ -477,6 +583,9 @@ struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *, int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); uint32_t lpfc_drain_txq(struct lpfc_hba *); +#ifndef NO_APEX +void lpfc_set_ndlps_fcp_priority(struct lpfc_nodelist *); +#endif void lpfc_clr_rrq_active(struct lpfc_hba *, uint16_t, struct lpfc_node_rrq *); int lpfc_test_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, uint16_t); void lpfc_handle_rrq_active(struct lpfc_hba *); @@ -499,9 +608,9 @@ int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, struct sli4_wcqe_xri_aborted *); +int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t); void lpfc_sli_abts_recover_port(struct lpfc_vport *, struct lpfc_nodelist *); -int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); @@ -586,10 +695,25 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, int); void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd, struct lpfc_sli4_hdw_queue *qp); +void lpfc_mode_sense_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *p_io_in, + struct lpfc_iocbq *p_io_out); +int lpfc_issue_scsi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct lpfc_scsi_io_req *cmd_req); + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +void lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd); +#endif +#if defined(BUILD_NVME) void lpfc_nvme_cmd_template(void); void lpfc_nvmet_cmd_template(void); -void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn); +void lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; +#endif +void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + uint32_t stat, uint32_t param); extern int lpfc_no_hba_reset_cnt; extern unsigned long lpfc_no_hba_reset[]; +extern int lpfc_acqe_cgn_frequency; +extern int lpfc_fabric_cgn_frequency; +extern int lpfc_use_cgn_signal; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index e672fa9e8..fe114d4ab 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -100,21 +100,274 @@ lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); } +/** + * lpfc_ct_unsol_cmpl : Completion callback function for unsol ct commands + * @phba : pointer to lpfc hba data structure. + * @cmdiocb : pointer to lpfc command iocb data structure. + * @rspiocb : pointer to lpfc response iocb data structure. + * + * This routine is the callback function for issuing unsol ct reject command. + * The memory allocated in the reject command path is freed up here. + **/ +static void +lpfc_ct_unsol_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *mp, *bmp; + + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + if (ndlp) + lpfc_nlp_put(ndlp); + + mp = cmdiocb->context2; + bmp = cmdiocb->context3; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + cmdiocb->context2 = NULL; + } + + if (bmp) { + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + kfree(bmp); + cmdiocb->context3 = NULL; + } + + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** + * lpfc_ct_reject_event : Issue reject for unhandled E2E commands + * @ndlp : pointer to a node-list data structure. + * ct_req : pointer to the CT request data structure. + * rx_id : ulp_context of the received UNSOL CT command + * ox_id : ox_id of the UNSOL CT command + * + * This routine is invoked by the lpfc_ct_handle_e2e routine for sending + * reject response. Reject response is sent for the unhandled E2E commands. + **/ +static void +lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, + struct lpfc_sli_ct_request *ct_req, + u16 ulp_context, u16 ox_id) +{ + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ct_request *ct_rsp; + struct lpfc_iocbq *cmdiocbq = NULL; + struct lpfc_dmabuf *bmp = NULL; + struct lpfc_dmabuf *mp = NULL; + struct ulp_bde64 *bpl; + IOCB_t *icmd; + u8 rc = 0; + + /* fill in BDEs for command */ + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) { + rc = 1; + goto ct_e2e_exit; + } + + mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp->phys); + if (!mp->virt) { + rc = 2; + goto ct_e2e_free_mp; + } + + /* Allocate buffer for Buffer ptr list */ + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) { + rc = 3; + goto ct_e2e_free_mpvirt; + } + + bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &bmp->phys); + if (!bmp->virt) { + rc = 4; + goto ct_e2e_free_bmp; + } + + INIT_LIST_HEAD(&mp->list); + INIT_LIST_HEAD(&bmp->list); + + bpl = (struct ulp_bde64 *)bmp->virt; + memset(bpl, 0, sizeof(struct ulp_bde64)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); + bpl->tus.f.bdeFlags = BUFF_TYPE_BLP_64; + bpl->tus.f.bdeSize = (LPFC_CT_PREAMBLE - 4); + bpl->tus.w = le32_to_cpu(bpl->tus.w); + + ct_rsp = (struct lpfc_sli_ct_request *)mp->virt; + memset(ct_rsp, 0, sizeof(struct lpfc_sli_ct_request)); + + ct_rsp->RevisionId.bits.Revision = SLI_CT_REVISION; + ct_rsp->RevisionId.bits.InId = 0; + ct_rsp->FsType = ct_req->FsType; + ct_rsp->FsSubType = ct_req->FsSubType; + ct_rsp->CommandResponse.bits.Size = 0; + ct_rsp->CommandResponse.bits.CmdRsp = + cpu_to_be16(SLI_CT_RESPONSE_FS_RJT); + ct_rsp->ReasonCode = SLI_CT_REQ_NOT_SUPPORTED; + ct_rsp->Explanation = SLI_CT_NO_ADDITIONAL_EXPL; + + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + rc = 5; + goto ct_e2e_free_bmpvirt; + } + + icmd = &cmdiocbq->iocb; + icmd->un.genreq64.bdl.ulpIoTag32 = 0; + icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); + icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.genreq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.genreq64.w5.hcsw.Fctl = (LS | LA); + icmd->un.genreq64.w5.hcsw.Dfctl = 0; + icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; + icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + + /* Save for completion so we can release these resources */ + cmdiocbq->context1 = lpfc_nlp_get(ndlp); + cmdiocbq->context2 = (uint8_t *)mp; + cmdiocbq->context3 = (uint8_t *)bmp; + cmdiocbq->iocb_cmpl = lpfc_ct_unsol_cmpl; + icmd->ulpContext = ulp_context;; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = ox_id; + icmd->un.ulpWord[3] = + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + icmd->ulpTimeout = (3 * phba->fc_ratov); + + cmdiocbq->retry = 0; + cmdiocbq->vport = vport; + cmdiocbq->context_un.ndlp = NULL; + cmdiocbq->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + if (!rc) + return; + + rc = 6; + lpfc_nlp_put(ndlp); + lpfc_sli_release_iocbq(phba, cmdiocbq); +ct_e2e_free_bmpvirt: + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); +ct_e2e_free_bmp: + kfree(bmp); +ct_e2e_free_mpvirt: + lpfc_mbuf_free(phba, mp->virt, mp->phys); +ct_e2e_free_mp: + kfree(mp); +ct_e2e_exit: + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6440 UNSOL CT Rsp err %d Data: x%x\n", + rc, vport->fc_flag); +} + +/** + * lpfc_ct_handle_e2e- Process an unsolicited E2E event data buffer + * @phba: pointer to lpfc hba data structure. + * @ctiocb: pointer to lpfc E2E CT command iocb data structure. + * + * This routine is used for processing the IOCB associated with a unsolicited + * E2E event. It first determines whether there is an existing ndlp that matches + * the DID from the unsolicited IOCB. If not, it will return. The E2E-CT command + * from the unsolicited IOCB is then used to invoke the proper routine and to + * set up proper state of the discovery state machine. + * + **/ +static void +lpfc_ct_handle_e2e(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) +{ + struct lpfc_sli_ct_request *ct_req; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_vport *vport = NULL; + IOCB_t *icmd = &ctiocbq->iocb; + u32 did = 0, vpi; + u32 e2e_cmd; + + vpi = ctiocbq->iocb.unsli3.rcvsli3.vpi; + vport = lpfc_find_vport_by_vpid(phba, vpi); + if (!vport) { + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "6437 Unsol CT : VPORT NULL vpi : x%x\n", + vpi); + return; + } + + did = ctiocbq->iocb.un.rcvels.remoteID; + if (icmd->ulpStatus) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6438 Unsol CT: status:x%x/x%x did : x%x\n", + icmd->ulpStatus, icmd->un.ulpWord[4], did); + return; + } + + /* Ignore traffic received during vport shutdown */ + if (vport->fc_flag & FC_UNLOADING) + return; + + ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6439 Unsol CT:NDLP Not Found for DID : x%x", + did); + return; + } + + ct_req = ((struct lpfc_sli_ct_request *) + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); + + e2e_cmd = ct_req->CommandResponse.bits.CmdRsp; + switch (e2e_cmd) { + case 0: + default: + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6442 : E2E Cmd : x%x Not Supported\n", + e2e_cmd); + lpfc_ct_reject_event(ndlp, ct_req, + ctiocbq->iocb.ulpContext, + ctiocbq->iocb.unsli3.rcvsli3.ox_id); + return; + } +} + +/** + * lpfc_ct_unsol_event - Process an unsolicited event from a ct sli ring + * @phba: pointer to lpfc hba data structure. + * @pring: pointer to a SLI ring. + * @ctiocbq: pointer to lpfc ct iocb data structure. + * + * This routine is used to process an unsolicited event received from a SLI + * (Service Level Interface) ring. The actual processing of the data buffer + * associated with the unsolicited event is done by invoking appropiate routine + * after properly set up the iocb buffer from the SLI ring on which the + * unsolicited event was received. + **/ void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) + struct lpfc_iocbq *ctiocbq) { struct lpfc_dmabuf *mp = NULL; - IOCB_t *icmd = &piocbq->iocb; + IOCB_t *icmd = &ctiocbq->iocb; int i; struct lpfc_iocbq *iocbq; - dma_addr_t paddr; + dma_addr_t dma_addr; uint32_t size; struct list_head head; - struct lpfc_dmabuf *bdeBuf; + struct lpfc_sli_ct_request *ct_req; + struct lpfc_dmabuf *bdeBuf1 = ctiocbq->context2; + struct lpfc_dmabuf *bdeBuf2 = ctiocbq->context3; - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) - return; + ctiocbq->context1 = NULL; + ctiocbq->context2 = NULL; + ctiocbq->context3 = NULL; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -128,46 +381,76 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; } - /* If there are no BDEs associated with this IOCB, - * there is nothing to do. + /* If there are no BDEs associated + * with this IOCB, there is nothing to do. */ if (icmd->ulpBdeCount == 0) return; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + ctiocbq->context2 = bdeBuf1; + if (icmd->ulpBdeCount == 2) + ctiocbq->context3 = bdeBuf2; + } else { + dma_addr = getPaddr(icmd->un.cont64[0].addrHigh, + icmd->un.cont64[0].addrLow); + ctiocbq->context2 = lpfc_sli_ringpostbuf_get(phba, pring, + dma_addr); + if (icmd->ulpBdeCount == 2) { + dma_addr = getPaddr(icmd->un.cont64[1].addrHigh, + icmd->un.cont64[1].addrLow); + ctiocbq->context3 = lpfc_sli_ringpostbuf_get(phba, + pring, + dma_addr); + } + } + + ct_req = ((struct lpfc_sli_ct_request *) + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); + + /* Check if request is for E2E */ + if (ct_req->FsType == SLI_CT_MANAGEMENT_SERVICE && + ct_req->FsSubType == SLI_CT_E2E_Subtypes) { + lpfc_ct_handle_e2e(phba, ctiocbq); + } else { + if (!lpfc_bsg_ct_unsol_event(phba, pring, ctiocbq)) + return; + } + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); + list_add_tail(&head, &ctiocbq->list); list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; if (icmd->ulpBdeCount == 0) continue; - bdeBuf = iocbq->context2; + bdeBuf1 = iocbq->context2; iocbq->context2 = NULL; size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); - lpfc_in_buf_free(phba, bdeBuf); + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf1, size); + lpfc_in_buf_free(phba, bdeBuf1); if (icmd->ulpBdeCount == 2) { - bdeBuf = iocbq->context3; + bdeBuf2 = iocbq->context3; iocbq->context3 = NULL; size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf2, size); - lpfc_in_buf_free(phba, bdeBuf); + lpfc_in_buf_free(phba, bdeBuf2); } } list_del(&head); } else { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); + list_add_tail(&head, &ctiocbq->list); list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; if (icmd->ulpBdeCount == 0) lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); for (i = 0; i < icmd->ulpBdeCount; i++) { - paddr = getPaddr(icmd->un.cont64[i].addrHigh, - icmd->un.cont64[i].addrLow); + dma_addr = getPaddr(icmd->un.cont64[i].addrHigh, + icmd->un.cont64[i].addrLow); mp = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); + dma_addr); size = icmd->un.cont64[i].tus.f.bdeSize; lpfc_ct_unsol_buffer(phba, iocbq, mp, size); lpfc_in_buf_free(phba, mp); @@ -714,7 +997,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a GID_FT completing so the gidft_inp counter was * incremented before the GID_FT was issued to the wire. */ - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; /* * Skip processing the NS response @@ -742,16 +1026,19 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; /* CT command is being retried */ - vport->gidft_inp--; rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->fc_ns_retry, type); if (rc == 0) goto out; + else { /* Unable to send NS cmd */ + if (vport->gidft_inp) + vport->gidft_inp--; + } } if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0257 GID_FT Query error: 0x%x 0x%x\n", irsp->ulpStatus, vport->fc_ns_retry); } else { @@ -762,9 +1049,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0208 NameServer Rsp Data: x%x x%x " - "sz x%x\n", + "x%x x%x sz x%x\n", vport->fc_flag, CTreq->un.gid.Fc4Type, + vport->num_disc_nodes, + vport->gidft_inp, irsp->un.genreq64.bdl.bdeSize); lpfc_ns_rsp(vport, @@ -810,7 +1099,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } else { /* NameServer Rsp Error */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0241 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", CTrsp->CommandResponse.bits.CmdRsp, @@ -824,7 +1113,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation); } - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; } lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -917,7 +1207,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a GID_PT completing so the gidft_inp counter was * incremented before the GID_PT was issued to the wire. */ - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; /* * Skip processing the NS response @@ -941,16 +1232,19 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, vport->fc_ns_retry++; /* CT command is being retried */ - vport->gidft_inp--; rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_PT, vport->fc_ns_retry, GID_PT_N_PORT); if (rc == 0) goto out; + else { /* Unable to send NS cmd */ + if (vport->gidft_inp) + vport->gidft_inp--; + } } if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4103 GID_FT Query error: 0x%x 0x%x\n", irsp->ulpStatus, vport->fc_ns_retry); } else { @@ -960,9 +1254,13 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4105 NameServer Rsp Data: x%x x%x\n", + "4105 NameServer Rsp Data: x%x x%x " + "x%x x%x sz x%x\n", vport->fc_flag, - CTreq->un.gid.Fc4Type); + CTreq->un.gid.Fc4Type, + vport->num_disc_nodes, + vport->gidft_inp, + irsp->un.genreq64.bdl.bdeSize); lpfc_ns_rsp(vport, outp, @@ -1007,7 +1305,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } else { /* NameServer Rsp Error */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4109 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", CTrsp->CommandResponse.bits.CmdRsp, @@ -1022,8 +1320,14 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (uint32_t)CTrsp->ReasonCode, (uint32_t)CTrsp->Explanation); } - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6450 GID_PT cmpl inp %d disc %d\n", + vport->gidft_inp, vport->num_disc_nodes); + /* Link up / RSCN discovery */ if ((vport->num_disc_nodes == 0) && (vport->gidft_inp == 0)) { @@ -1133,7 +1437,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0267 NameServer GFF Rsp " "x%x Error (%d %d) Data: x%x x%x\n", did, irsp->ulpStatus, irsp->un.ulpWord[4], @@ -1158,6 +1462,11 @@ out: /* Link up / RSCN discovery */ if (vport->num_disc_nodes) vport->num_disc_nodes--; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6451 GFF_ID cmpl inp %d disc %d\n", + vport->gidft_inp, vport->num_disc_nodes); + if (vport->num_disc_nodes == 0) { /* * The driver has cycled through all Nports in the RSCN payload. @@ -1226,9 +1535,8 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ndlp->nlp_fc4_type |= NLP_FC4_NVME; lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "3064 Setting ndlp x%px, DID x%06x " - "with FC4 x%08x, Data: x%08x x%08x " - "%d\n", + "3064 Setting ndlp x%px, DID x%06x with " + "FC4 x%08x, Data: x%08x x%08x %d\n", ndlp, did, ndlp->nlp_fc4_type, FC_TYPE_FCP, FC_TYPE_NVME, ndlp->nlp_state); @@ -1256,7 +1564,7 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } } else - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3065 GFT_ID failed x%08x\n", irsp->ulpStatus); lpfc_ct_free_iocb(phba, cmdiocb); @@ -1305,7 +1613,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode); if (irsp->ulpStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0268 NS cmd x%x Error (x%x x%x)\n", cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]); @@ -1828,7 +2136,7 @@ ns_cmd_free_mpvirt: ns_cmd_free_mp: kfree(mp); ns_cmd_exit: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n", cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt); return 1; @@ -1941,6 +2249,15 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; case SLI_MGMT_RPA: + if (vport->fc_flag & FC_CT_CGN_RPA) { + vport->fc_flag &= ~FC_CT_CGN_RPA; + if (phba->cmf_active_mode == LPFC_CFG_OFF) + return; + lpfc_vlog_msg(vport, KERN_WARNING, + LOG_DISCOVERY | LOG_CGN_MGMT, + "6435 E2E FDMI RPA failure\n"); + return; + } if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) { /* Fallback to FDMI-1 */ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR; @@ -1977,6 +2294,38 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0); break; + case SLI_MGMT_RPA: + if (vport->port_type == LPFC_PHYSICAL_PORT && + phba->sli4_hba.pc_sli4_params.E2E_attr) { + if (vport->fc_flag & FC_CT_CGN_RPA) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_CGN_MGMT, + "6436 E2E FDMI RPA Success\n"); + vport->fc_flag &= ~FC_CT_CGN_RPA; + return; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6210 Issue Vendor E2E FDMI %x\n", + phba->sli4_hba.pc_sli4_params.E2E_attr); + + /* CGN is only for the phyical port, no vports */ + if (lpfc_fdmi_cmd(vport, ndlp, cmd, + LPFC_FDMI_VENDOR_ATTR_cgn) == 0) + vport->fc_flag |= FC_CT_CGN_RPA; + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6458 Send E2E FDMI:%x Flag x%x\n", + phba->sli4_hba.pc_sli4_params. + E2E_attr, + phba->link_flag); + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6459 No FDMI E2E support - " + "RPA Success\n"); + } + break; } return; } @@ -2021,10 +2370,13 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) * DHBA -> DPRT -> RHBA -> RPA (physical port) * DPRT -> RPRT (vports) */ - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT) { + /* For extra ELXE2EM RPA */ + vport->fc_flag &= ~FC_CT_CGN_RPA; lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); - else + } else { lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0); + } /* Since this code path registers all the port attributes * we can just return without further checking. @@ -2050,7 +2402,7 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) } /* Routines for all individual HBA attributes */ -static int +int lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { struct lpfc_fdmi_attr_entry *ae; @@ -2066,7 +2418,7 @@ lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) ad->AttrType = cpu_to_be16(RHBA_NODENAME); return size; } -static int +int lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2091,7 +2443,7 @@ lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { struct lpfc_hba *phba = vport->phba; @@ -2112,7 +2464,7 @@ lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) return size; } -static int +int lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2133,7 +2485,7 @@ lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2155,7 +2507,7 @@ lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2187,7 +2539,7 @@ lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2208,7 +2560,7 @@ lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2233,7 +2585,7 @@ lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2254,7 +2606,7 @@ lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2277,7 +2629,7 @@ lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2293,7 +2645,7 @@ lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2312,7 +2664,7 @@ lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2329,7 +2681,7 @@ lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2346,7 +2698,7 @@ lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2364,7 +2716,7 @@ lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2386,7 +2738,7 @@ lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2403,7 +2755,7 @@ lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2425,7 +2777,7 @@ lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport, } /* Routines for all individual PORT attributes */ -static int +int lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2436,7 +2788,6 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, ae = &ad->AttrValue; memset(ae, 0, sizeof(*ae)); - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ @@ -2451,7 +2802,7 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2505,7 +2856,7 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2575,7 +2926,7 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2595,7 +2946,7 @@ lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2617,7 +2968,7 @@ lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2638,7 +2989,7 @@ lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2656,7 +3007,7 @@ lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2674,7 +3025,7 @@ lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2692,7 +3043,7 @@ lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2711,7 +3062,7 @@ lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_class(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2726,7 +3077,7 @@ lpfc_fdmi_port_attr_class(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2744,7 +3095,7 @@ lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2754,7 +3105,6 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, ae = &ad->AttrValue; memset(ae, 0, sizeof(*ae)); - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ @@ -2768,7 +3118,7 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2784,7 +3134,7 @@ lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2800,7 +3150,7 @@ lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2815,7 +3165,7 @@ lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2836,7 +3186,7 @@ lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2857,7 +3207,7 @@ lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2867,7 +3217,8 @@ lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, ae = &ad->AttrValue; memset(ae, 0, sizeof(*ae)); - strncpy(ae->un.AttrString, "Smart SAN Version 2.0", + strncpy(ae->un.AttrString, + "Smart SAN Version 2.0", sizeof(ae->un.AttrString)); len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); @@ -2878,7 +3229,7 @@ lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2899,7 +3250,7 @@ lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2910,16 +3261,16 @@ lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport, /* SRIOV (type 3) is not supported */ if (vport->vpi) - ae->un.AttrInt = cpu_to_be32(2); /* NPIV */ + ae->un.AttrInt = cpu_to_be32(2); /* NPIV */ else - ae->un.AttrInt = cpu_to_be32(1); /* Physical */ + ae->un.AttrInt = cpu_to_be32(1); /* Physical */ size = FOURBYTES + sizeof(uint32_t); ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO); return size; } -static int +int lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2934,7 +3285,7 @@ lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport, return size; } -static int +int lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { @@ -2949,6 +3300,30 @@ lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, return size; } +int +lpfc_fdmi_vendor_attr_cgn(struct lpfc_vport *vport, + struct lpfc_fdmi_attr_def *ad) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_fdmi_attr_entry *ae; + uint32_t len, size; + char cgnrevision[16]; + + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, 256); + + sprintf(cgnrevision, "ELXE2EM:%04d", + phba->sli4_hba.pc_sli4_params.E2E_attr); + strncpy(ae->un.AttrString, &cgnrevision[0], + sizeof(ae->un.AttrString)); + len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); + len += (len & 3) ? (4 - (len & 3)) : 4; + size = FOURBYTES + len; + ad->AttrLen = cpu_to_be16(size); + ad->AttrType = cpu_to_be16(RPRT_VENDOR_CGN); + return size; +} + /* RHBA attribute jump table */ int (*lpfc_fdmi_hba_action[]) (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = { @@ -3000,6 +3375,7 @@ int (*lpfc_fdmi_port_action[]) lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */ + lpfc_fdmi_vendor_attr_cgn, /* bit23 RPRT_VENDOR_CGN */ }; /** @@ -3029,7 +3405,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_fdmi_attr_block *ab = NULL; int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad); void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); + struct lpfc_iocbq *); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) return 0; @@ -3255,9 +3631,17 @@ fdmi_cmd_exit: * the worker thread. **/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_delayed_disc_tmo(unsigned long ptr) +#else lpfc_delayed_disc_tmo(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_vport *vport = (struct lpfc_vport *)ptr; +#else struct lpfc_vport *vport = from_timer(vport, t, delayed_disc_tmo); +#endif struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; @@ -3284,6 +3668,10 @@ void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); +#ifndef BUILD_BRCMFCOE + struct lpfc_nodelist *ndlp = NULL; + int rc = 0; +#endif spin_lock_irq(shost->host_lock); if (!(vport->fc_flag & FC_DISC_DELAYED)) { @@ -3293,7 +3681,18 @@ lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport) vport->fc_flag &= ~FC_DISC_DELAYED; spin_unlock_irq(shost->host_lock); +#ifndef BUILD_BRCMFCOE + ndlp = lpfc_findnode_did(vport, Fabric_DID); + /* check for authentication requirement */ + rc = lpfc_auth_start(vport, ndlp); + if (rc) { + if (vport->port_state != LPFC_FDISC) + lpfc_start_fdiscs(vport->phba); + lpfc_do_scr_ns_plogi(vport->phba, vport); + } +#else lpfc_do_scr_ns_plogi(vport->phba, vport); +#endif } void diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3c9248d24..475551aab 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -31,14 +31,18 @@ #include #include #include +#include #include #include #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -107,10 +111,12 @@ MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, "Set debugfs slow ring trace depth"); /* This MUST be a power of 2 */ +#ifdef BUILD_NVME static int lpfc_debugfs_max_nvmeio_trc; module_param(lpfc_debugfs_max_nvmeio_trc, int, 0444); MODULE_PARM_DESC(lpfc_debugfs_max_nvmeio_trc, "Set debugfs NVME IO trace depth"); +#endif static int lpfc_debugfs_mask_disc_trc; module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO); @@ -170,7 +176,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += scnprintf(buf+len, size-len, buffer, + len += scnprintf(buf + len, size - len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { @@ -181,7 +187,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += scnprintf(buf+len, size-len, buffer, + len += scnprintf(buf + len, size - len, buffer, dtp->data1, dtp->data2, dtp->data3); } @@ -236,7 +242,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += scnprintf(buf+len, size-len, buffer, + len += scnprintf(buf + len, size - len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { @@ -247,7 +253,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += scnprintf(buf+len, size-len, buffer, + len += scnprintf(buf + len, size - len, buffer, dtp->data1, dtp->data2, dtp->data3); } @@ -307,7 +313,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) i = lpfc_debugfs_last_hbq; - len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i); + len += scnprintf(buf + len, size - len, "HBQ %d Info\n", i); hbqs = &phba->hbqs[i]; posted = 0; @@ -315,21 +321,21 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) posted++; hip = lpfc_hbq_defs[i]; - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n", hip->hbq_index, hip->profile, hip->rn, hip->buffer_count, hip->init_count, hip->add_count, posted); raw_index = phba->hbq_get[i]; getidx = le32_to_cpu(raw_index); - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; for (j=0; jentry_count; j++) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "%03d: %08x %04x %05x ", j, le32_to_cpu(hbqe->bde.addrLow), le32_to_cpu(hbqe->bde.tus.w), @@ -341,16 +347,16 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) low = hbqs->hbqPutIdx - posted; if (low >= 0) { if ((j >= hbqs->hbqPutIdx) || (j < low)) { - len += scnprintf(buf + len, size - len, - "Unused\n"); + len += scnprintf(buf + len, + size - len, "Unused\n"); goto skipit; } } else { if ((j >= hbqs->hbqPutIdx) && (j < (hbqs->entry_count+low))) { - len += scnprintf(buf + len, size - len, - "Unused\n"); + len += scnprintf(buf + len, + size - len, "Unused\n"); goto skipit; } } @@ -360,7 +366,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); if (phys == le32_to_cpu(hbqe->bde.addrLow)) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "Buf%d: x%px %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); found = 1; @@ -369,7 +375,8 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) i++; } if (!found) { - len += scnprintf(buf+len, size-len, "No DMAinfo?\n"); + len += scnprintf(buf + len, + size - len, "No DMAinfo?\n"); } skipit: hbqe++; @@ -568,6 +575,71 @@ lpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size) return strnlen(buf, size); } +/** + * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine clears multi-XRI pools statistics when buf contains "clear". + * + * Return Value: + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + char mybuf[64]; + char *pbuf; + u32 i; + u32 hwq_count; + struct lpfc_sli4_hdw_queue *qp; + struct lpfc_multixri_pool *multixri_pool; + + if (nbytes > 64) + nbytes = 64; + + memset(mybuf, 0, sizeof(mybuf)); + + if (copy_from_user(mybuf, buf, nbytes)) + return -EFAULT; + pbuf = &mybuf[0]; + + if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) { + hwq_count = phba->cfg_hdw_queue; + for (i = 0; i < hwq_count; i++) { + qp = &phba->sli4_hba.hdwq[i]; + multixri_pool = qp->p_multixri_pool; + if (!multixri_pool) + continue; + + qp->empty_io_bufs = 0; + multixri_pool->pbl_empty_count = 0; +#ifdef LPFC_MXP_STAT + multixri_pool->above_limit_count = 0; + multixri_pool->below_limit_count = 0; + multixri_pool->stat_max_hwm = 0; + multixri_pool->local_pbl_hit_count = 0; + multixri_pool->other_pbl_hit_count = 0; + + multixri_pool->stat_pbl_count = 0; + multixri_pool->stat_pvt_count = 0; + multixri_pool->stat_busy_count = 0; + multixri_pool->stat_snapshot_taken = 0; +#endif + } + return strlen(pbuf); + } + + return -EINVAL; +} #ifdef LPFC_HDWQ_LOCK_STAT static int lpfc_debugfs_last_lock; @@ -676,7 +748,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) off = 0; spin_lock_irq(&phba->hbalock); - len += scnprintf(buf+len, size-len, "HBA SLIM\n"); + len += scnprintf(buf + len, size - len, "HBA SLIM\n"); lpfc_memcpy_from_slim(buffer, phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024); @@ -690,7 +762,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) i = 1024; while (i > 0) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -734,11 +806,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) off = 0; spin_lock_irq(&phba->hbalock); - len += scnprintf(buf+len, size-len, "SLIM Mailbox\n"); + len += scnprintf(buf + len, size - len, "SLIM Mailbox\n"); ptr = (uint32_t *)phba->slim2p.virt; i = sizeof(MAILBOX_t); while (i > 0) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -747,11 +819,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) off += (8 * sizeof(uint32_t)); } - len += scnprintf(buf+len, size-len, "SLIM PCB\n"); + len += scnprintf(buf + len, size - len, "SLIM PCB\n"); ptr = (uint32_t *)phba->pcb; i = sizeof(PCB_t); while (i > 0) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -764,7 +836,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) for (i = 0; i < 4; i++) { pgpp = &phba->port_gp[i]; pring = &psli->sli3_ring[i]; - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "Ring %d: CMD GetInx:%d " "(Max:%d Next:%d " "Local:%d flg:x%x) " @@ -781,7 +853,8 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) word1 = readl(phba->CAregaddr); word2 = readl(phba->HSregaddr); word3 = readl(phba->HCregaddr); - len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " + len += scnprintf(buf + len, + size - len, "HA:%08x CA:%08x HS:%08x " "HC:%08x\n", word0, word1, word2, word3); } spin_unlock_irq(&phba->hbalock); @@ -809,22 +882,26 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) int len = 0; int i, iocnt, outio, cnt; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; unsigned char *statep; +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_hba *phba = vport->phba; struct nvme_fc_local_port *localport; struct nvme_fc_remote_port *nrport = NULL; struct lpfc_nvme_rport *rport; +#endif +#endif cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); outio = 0; - len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n"); + len += scnprintf(buf + len, size - len, "\nFCP Nodelist Entries ...\n"); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { iocnt = 0; if (!cnt) { - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "Missing Nodelist Entries\n"); break; } @@ -862,34 +939,37 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) default: statep = "UNKNOWN"; } - len += scnprintf(buf+len, size-len, "%s DID:x%06x ", + len += scnprintf(buf + len, size - len, "%s DID:x%06x ", statep, ndlp->nlp_DID); - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "WWPN x%llx ", wwn_to_u64(ndlp->nlp_portname.u.wwn)); - len += scnprintf(buf+len, size-len, + len += scnprintf(buf + len, size - len, "WWNN x%llx ", wwn_to_u64(ndlp->nlp_nodename.u.wwn)); if (ndlp->nlp_flag & NLP_RPI_REGISTERED) - len += scnprintf(buf+len, size-len, "RPI:%03d ", + len += scnprintf(buf + len, size - len, "RPI:%03d ", ndlp->nlp_rpi); else - len += scnprintf(buf+len, size-len, "RPI:none "); - len += scnprintf(buf+len, size-len, "flag:x%08x ", + len += scnprintf(buf + len, size - len, "RPI:none "); + len += scnprintf(buf + len, size - len, "flag:x%08x ", ndlp->nlp_flag); if (!ndlp->nlp_type) - len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); + len += scnprintf(buf + len, size - len, + "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) - len += scnprintf(buf+len, size-len, "FC_NODE "); + len += scnprintf(buf + len, size - len, "FC_NODE "); if (ndlp->nlp_type & NLP_FABRIC) { - len += scnprintf(buf+len, size-len, "FABRIC "); + len += scnprintf(buf + len, size - len, "FABRIC "); iocnt = 0; } if (ndlp->nlp_type & NLP_FCP_TARGET) - len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ", - ndlp->nlp_sid); + len += scnprintf(buf + len, + size - len, "FCP_TGT sid:%d ", + ndlp->nlp_sid); if (ndlp->nlp_type & NLP_FCP_INITIATOR) - len += scnprintf(buf+len, size-len, "FCP_INITIATOR "); + len += scnprintf(buf + len, + size - len, "FCP_INITIATOR "); if (ndlp->nlp_type & NLP_NVME_TARGET) len += scnprintf(buf + len, size - len, "NVME_TGT sid:%d ", @@ -897,9 +977,9 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) if (ndlp->nlp_type & NLP_NVME_INITIATOR) len += scnprintf(buf + len, size - len, "NVME_INITIATOR "); - len += scnprintf(buf+len, size-len, "usgmap:%x ", + len += scnprintf(buf + len, size - len, "usgmap:%x ", ndlp->nlp_usg_map); - len += scnprintf(buf+len, size-len, "refcnt:%x", + len += scnprintf(buf + len, size - len, "refcnt:%x", kref_read(&ndlp->kref)); if (iocnt) { i = atomic_read(&ndlp->cmd_pending); @@ -910,13 +990,15 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) } len += scnprintf(buf + len, size - len, "defer:%x ", ndlp->nlp_defer_did); - len += scnprintf(buf+len, size-len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); } spin_unlock_irq(shost->host_lock); len += scnprintf(buf + len, size - len, "\nOutstanding IO x%x\n", outio); +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) { len += scnprintf(buf + len, size - len, "\nNVME Targetport Entry ...\n"); @@ -993,26 +1075,29 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) /* An NVME rport can have multiple roles. */ if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) - len += scnprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "INITIATOR "); if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) - len += scnprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "TARGET "); if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) - len += scnprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "DISCSRVC "); if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | FC_PORT_ROLE_NVME_TARGET | FC_PORT_ROLE_NVME_DISCOVERY)) - len += scnprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "UNKNOWN ROLE x%x", nrport->port_role); /* Terminate the string. */ - len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); } spin_unlock_irq(shost->host_lock); + out_exit: +#endif +#endif return len; } @@ -1032,6 +1117,8 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) static int lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) { + int len = 0; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_tgtport *tgtp; struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; @@ -1041,7 +1128,6 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) uint64_t data1, data2, data3; uint64_t tot, totin, totout; int cnt, i; - int len = 0; if (phba->nvmet_support) { if (!phba->targetport) @@ -1123,7 +1209,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&tgtp->xmt_abort_rsp), atomic_read(&tgtp->xmt_abort_rsp_error)); - len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); cnt = 0; spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); @@ -1138,8 +1224,8 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) "ABORT: %d ctx entries\n", cnt); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, next_ctxp, - &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, - list) { + &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, + list) { if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) break; len += scnprintf(buf + len, size - len, @@ -1234,6 +1320,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&lport->cmpl_fcp_err)); } +#endif return len; } @@ -1299,8 +1386,88 @@ buffer_done: return len; } +void +lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) +{ + uint64_t seg1, seg2, seg3, seg4; + uint64_t segsum; + + if (!lpfc_cmd->ts_last_cmd || + !lpfc_cmd->ts_cmd_start || + !lpfc_cmd->ts_cmd_wqput || + !lpfc_cmd->ts_isr_cmpl || + !lpfc_cmd->ts_data_io) + return; + + if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start) + return; + if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd) + return; + if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start) + return; + if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput) + return; + if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl) + return; + /* + * Segment 1 - Time from Last FCP command cmpl is handed + * off to NVME Layer to start of next command. + * Segment 2 - Time from Driver receives a IO cmd start + * from NVME Layer to WQ put is done on IO cmd. + * Segment 3 - Time from Driver WQ put is done on IO cmd + * to MSI-X ISR for IO cmpl. + * Segment 4 - Time from MSI-X ISR for IO cmpl to when + * cmpl is handled off to the NVME Layer. + */ + seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd; + if (seg1 > 5000000) /* 5 ms - for sequential IOs only */ + seg1 = 0; + + /* Calculate times relative to start of IO */ + seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start); + segsum = seg2; + seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start; + if (segsum > seg3) + return; + seg3 -= segsum; + segsum += seg3; + + seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start; + if (segsum > seg4) + return; + seg4 -= segsum; + + phba->ktime_data_samples++; + phba->ktime_seg1_total += seg1; + if (seg1 < phba->ktime_seg1_min) + phba->ktime_seg1_min = seg1; + else if (seg1 > phba->ktime_seg1_max) + phba->ktime_seg1_max = seg1; + phba->ktime_seg2_total += seg2; + if (seg2 < phba->ktime_seg2_min) + phba->ktime_seg2_min = seg2; + else if (seg2 > phba->ktime_seg2_max) + phba->ktime_seg2_max = seg2; + phba->ktime_seg3_total += seg3; + if (seg3 < phba->ktime_seg3_min) + phba->ktime_seg3_min = seg3; + else if (seg3 > phba->ktime_seg3_max) + phba->ktime_seg3_max = seg3; + phba->ktime_seg4_total += seg4; + if (seg4 < phba->ktime_seg4_min) + phba->ktime_seg4_min = seg4; + else if (seg4 > phba->ktime_seg4_max) + phba->ktime_seg4_max = seg4; + + lpfc_cmd->ts_last_cmd = 0; + lpfc_cmd->ts_cmd_start = 0; + lpfc_cmd->ts_cmd_wqput = 0; + lpfc_cmd->ts_isr_cmpl = 0; + lpfc_cmd->ts_data_io = 0; +} + /** - * lpfc_debugfs_nvmektime_data - Dump target node list to a buffer + * lpfc_debugfs_ioktime_data - Dump target node list to a buffer * @vport: The vport to gather target node info from. * @buf: The buffer to dump log into. * @size: The maximum amount of data to process. @@ -1313,13 +1480,13 @@ buffer_done: * not exceed @size. **/ static int -lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) +lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size) { struct lpfc_hba *phba = vport->phba; int len = 0; if (phba->nvmet_support == 0) { - /* NVME Initiator */ + /* Initiator */ len += scnprintf(buf + len, PAGE_SIZE - len, "ktime %s: Total Samples: %lld\n", (phba->ktime_on ? "Enabled" : "Disabled"), @@ -1329,8 +1496,8 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf( buf + len, PAGE_SIZE - len, - "Segment 1: Last NVME Cmd cmpl " - "done -to- Start of next NVME cnd (in driver)\n"); + "Segment 1: Last Cmd cmpl " + "done -to- Start of next Cmd (in driver)\n"); len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", @@ -1340,7 +1507,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) phba->ktime_seg1_max); len += scnprintf( buf + len, PAGE_SIZE - len, - "Segment 2: Driver start of NVME cmd " + "Segment 2: Driver start of Cmd " "-to- Firmware WQ doorbell\n"); len += scnprintf( buf + len, PAGE_SIZE - len, @@ -1363,7 +1530,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 4: MSI-X ISR cmpl -to- " - "NVME cmpl done\n"); + "Cmd cmpl done\n"); len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", @@ -1383,7 +1550,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) } /* NVME Target */ - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "ktime %s: Total Samples: %lld %lld\n", (phba->ktime_on ? "Enabled" : "Disabled"), phba->ktime_data_samples, @@ -1391,46 +1558,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) if (phba->ktime_data_samples == 0) return len; - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 1: MSI-X ISR Rcv cmd -to- " "cmd pass to NVME Layer\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg1_total, phba->ktime_data_samples), phba->ktime_seg1_min, phba->ktime_seg1_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 2: cmd pass to NVME Layer- " "-to- Driver rcv cmd OP (action)\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg2_total, phba->ktime_data_samples), phba->ktime_seg2_min, phba->ktime_seg2_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 3: Driver rcv cmd OP -to- " "Firmware WQ doorbell: cmd\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg3_total, phba->ktime_data_samples), phba->ktime_seg3_min, phba->ktime_seg3_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 4: Firmware WQ doorbell: cmd " "-to- MSI-X ISR for cmd cmpl\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg4_total, phba->ktime_data_samples), phba->ktime_seg4_min, phba->ktime_seg4_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 5: MSI-X ISR for cmd cmpl " "-to- NVME layer passed cmd done\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg5_total, phba->ktime_data_samples), @@ -1438,10 +1605,10 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) phba->ktime_seg5_max); if (phba->ktime_status_samples == 0) { - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Total: cmd received by MSI-X ISR " "-to- cmd completed on wire\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld " "max %08lld\n", div_u64(phba->ktime_seg10_total, @@ -1451,46 +1618,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) return len; } - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 6: NVME layer passed cmd done " "-to- Driver rcv rsp status OP\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg6_total, phba->ktime_status_samples), phba->ktime_seg6_min, phba->ktime_seg6_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 7: Driver rcv rsp status OP " "-to- Firmware WQ doorbell: status\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg7_total, phba->ktime_status_samples), phba->ktime_seg7_min, phba->ktime_seg7_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 8: Firmware WQ doorbell: status" " -to- MSI-X ISR for status cmpl\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg8_total, phba->ktime_status_samples), phba->ktime_seg8_min, phba->ktime_seg8_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Segment 9: MSI-X ISR for status cmpl " "-to- NVME layer passed status done\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg9_total, phba->ktime_status_samples), phba->ktime_seg9_min, phba->ktime_seg9_max); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Total: cmd received by MSI-X ISR -to- " "cmd completed on wire\n"); - len += scnprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg10_total, phba->ktime_status_samples), @@ -1547,7 +1714,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) if (!dtp->fmt) continue; - len += scnprintf(buf + len, size - len, dtp->fmt, + len += scnprintf(buf + len, size - len, dtp->fmt, dtp->data1, dtp->data2, dtp->data3); if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { @@ -1576,7 +1743,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) if (!dtp->fmt) continue; - len += scnprintf(buf + len, size - len, dtp->fmt, + len += scnprintf(buf + len, size - len, dtp->fmt, dtp->data1, dtp->data2, dtp->data3); if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { @@ -1602,42 +1769,50 @@ out: } /** - * lpfc_debugfs_cpucheck_data - Dump target node list to a buffer + * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer * @vport: The vport to gather target node info from. * @buf: The buffer to dump log into. * @size: The maximum amount of data to process. * * Description: - * This routine dumps the NVME statistics associated with @vport + * This routine dumps the NVME + SCSI statistics associated with @vport * * Return Value: * This routine returns the amount of bytes that were dumped into @buf and will * not exceed @size. **/ static int -lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) +lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size) { struct lpfc_hba *phba = vport->phba; struct lpfc_sli4_hdw_queue *qp; - int i, j, max_cnt; - int len = 0; + struct lpfc_hdwq_stat *c_stat; + int i, j, len; uint32_t tot_xmt; uint32_t tot_rcv; uint32_t tot_cmpl; + char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0}; - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPUcheck %s ", - (phba->cpucheck_on & LPFC_CHECK_NVME_IO ? - "Enabled" : "Disabled")); - if (phba->nvmet_support) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "%s\n", - (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ? - "Rcv Enabled\n" : "Rcv Disabled\n")); - } else { - len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); - } - max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ; + scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n"); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ", + (phba->hdwqstat_on & + (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ? + "Enabled" : "Disabled")); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ", + (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ? + "Enabled" : "Disabled")); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), "\n\n"); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; for (i = 0; i < phba->cfg_hdw_queue; i++) { qp = &phba->sli4_hba.hdwq[i]; @@ -1645,46 +1820,149 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) tot_rcv = 0; tot_xmt = 0; tot_cmpl = 0; - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { - tot_xmt += qp->cpucheck_xmt_io[j]; - tot_cmpl += qp->cpucheck_cmpl_io[j]; + + for_each_present_cpu(j) { + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j); + + /* Only display for this HDWQ */ + if (i != c_stat->hdwq_no) + continue; + + /* Only display non-zero counters */ + if (!c_stat->xmt_io && !c_stat->cmpl_io && + !c_stat->rcv_io) + continue; + + if (!tot_xmt && !tot_cmpl && !tot_rcv) { + /* Print HDWQ string only the first time */ + scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } + + tot_xmt += c_stat->xmt_io; + tot_cmpl += c_stat->cmpl_io; if (phba->nvmet_support) - tot_rcv += qp->cpucheck_rcv_io[j]; + tot_rcv += c_stat->rcv_io; + + scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + if (phba->nvmet_support) { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x RCV 0x%x |", + c_stat->xmt_io, c_stat->cmpl_io, + c_stat->rcv_io); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } else { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x |", + c_stat->xmt_io, c_stat->cmpl_io); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } } - /* Only display Hardware Qs with something */ + /* Check if nothing to display */ if (!tot_xmt && !tot_cmpl && !tot_rcv) continue; - len += scnprintf(buf + len, PAGE_SIZE - len, - "HDWQ %03d: ", i); - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { - /* Only display non-zero counters */ - if (!qp->cpucheck_xmt_io[j] && - !qp->cpucheck_cmpl_io[j] && - !qp->cpucheck_rcv_io[j]) - continue; - if (phba->nvmet_support) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPU %03d: %x/%x/%x ", j, - qp->cpucheck_rcv_io[j], - qp->cpucheck_xmt_io[j], - qp->cpucheck_cmpl_io[j]); - } else { - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPU %03d: %x/%x ", j, - qp->cpucheck_xmt_io[j], - qp->cpucheck_cmpl_io[j]); - } - } - len += scnprintf(buf + len, PAGE_SIZE - len, - "Total: %x\n", tot_xmt); - if (len >= max_cnt) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "Truncated ...\n"); - return len; + scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: "); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + if (phba->nvmet_support) { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n", + tot_xmt, tot_cmpl, tot_rcv); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } else { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x]\n\n", + tot_xmt, tot_cmpl); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; } } + +buffer_done: + len = strnlen(buf, size); + return len; +} + +/** + * lpfc_debugfs_ediflist_data - Dump target External DIF list to a buffer + * @vport: The vport to gather target External DIF info from. + * @buf: The buffer to dump log into. + * @size: The maximum amount of data to process. + * + * Description: + * This routine dumps current target External DIF list associated with @vport + * to @buf up to @size bytes of data. Each node entry in the dump will contain a + * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields. + * + * Return Value: + * This routine returns the amount of bytes that were dumped into @buf and will + * not exceed @size. + **/ +static int +lpfc_debugfs_ediflist_data(struct lpfc_vport *vport, char *buf, int size) +{ + int len = 0; + int cnt; + struct lpfc_external_dif_support *edifp; + unsigned char *statep, *name; + + cnt = (LPFC_EDIFLIST_SIZE / LPFC_EDIFLIST_ENTRY_SIZE); + + spin_lock_irq(&vport->external_dif_lock); + list_for_each_entry(edifp, &vport->external_dif_list, listentry) { + if (!cnt) { + len += scnprintf(buf + len, size - len, + "Missing External DIF Entries\n"); + break; + } + cnt--; + switch (edifp->state) { + case LPFC_EDSM_IGNORE: + statep = "IGNORE "; + break; + case LPFC_EDSM_INIT: + statep = "INIT "; + break; + case LPFC_EDSM_NEEDS_INQUIRY: + statep = "NEEDS_INQ"; + break; + case LPFC_EDSM_PATH_STANDBY: + statep = "STANDBY "; + break; + case LPFC_EDSM_PATH_READY: + statep = "READY "; + break; + case LPFC_EDSM_PATH_CHECK: + statep = "CHECK "; + break; + default: + statep = "UNKNOWN "; + } + len += scnprintf(buf + len, + size - len, "%s Device (x%x/x%llx) ", + statep, edifp->sid, edifp->lun); + name = (unsigned char *)&edifp->portName; + len += scnprintf(buf + len, size - len, + "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", + *name, *(name+1), *(name+2), *(name+3), + *(name+4), *(name+5), *(name+6), *(name+7)); + len += scnprintf(buf + len, size - len, + "dif_info:x%x inq:%d err3f:%d err4b:%d", + edifp->dif_info, edifp->inq_cnt, edifp->err3f_cnt, + edifp->err4b_cnt); + len += scnprintf(buf + len, size - len, "\n"); + } + spin_unlock_irq(&vport->external_dif_lock); return len; } @@ -2047,10 +2325,6 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, char *pbuf; int i; - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; - memset(mybuf, 0, sizeof(mybuf)); if (copy_from_user(mybuf, buf, nbytes)) @@ -2078,6 +2352,103 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, } #endif +int +lpfc_debugfs_ras_log_data(struct lpfc_hba *phba, char *buffer, int size) +{ + int copied = 0; + struct lpfc_dmabuf *dmabuf, *next; + + memset(buffer, 0, size); + + spin_lock_irq(&phba->hbalock); + if (phba->ras_fwlog.state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); + return -EINVAL; + } + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(dmabuf, next, + &phba->ras_fwlog.fwlog_buff_list, list) { + /* Check if copying will go over size and a '\0' char */ + if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) { + memcpy(buffer + copied, dmabuf->virt, + size - copied - 1); + copied += size - copied - 1; + break; + } + memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE); + copied += LPFC_RAS_MAX_ENTRY_SIZE; + } + return copied; +} + +static int +lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + +/** + * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer + * @inode: The inode pointer that contains a vport pointer. + * @file: The file pointer to attach the log output. + * + * Description: + * This routine is the entry point for the debugfs open file operation. It gets + * the vport from the i_private field in @inode, allocates the necessary buffer + * for the log, fills the buffer from the in-memory log for this vport, and then + * returns a pointer to that log in the private_data field in @file. + * + * Returns: + * This function returns zero if successful. On error it will return a negative + * error value. + **/ +static int +lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file) +{ + struct lpfc_hba *phba = inode->i_private; + struct lpfc_debug *debug; + int size; + int rc = -ENOMEM; + + spin_lock_irq(&phba->hbalock); + if (phba->ras_fwlog.state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); + rc = -EINVAL; + goto out; + } + spin_unlock_irq(&phba->hbalock); + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize; + debug->buffer = vmalloc(size); + if (!debug->buffer) + goto free_debug; + + debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size); + if (debug->len < 0) { + rc = -EINVAL; + goto free_buffer; + } + file->private_data = debug; + + return 0; + +free_buffer: + vfree(debug->buffer); +free_debug: + kfree(debug); +out: + return rc; +} + /** * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer * @inode: The inode pointer that contains a vport pointer. @@ -2162,6 +2533,13 @@ out: return rc; } +static int +lpfc_debugfs_dif_err_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) @@ -2186,7 +2564,7 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); else if (dent == phba->debug_InjErrNPortID) cnt = scnprintf(cbuf, 32, "0x%06x\n", - phba->lpfc_injerr_nportid); + phba->lpfc_injerr_nportid); else if (dent == phba->debug_InjErrWWPN) { memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); tmp = cpu_to_be64(tmp); @@ -2217,15 +2595,16 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, memset(dstbuf, 0, 33); size = (nbytes < 32) ? nbytes : 32; if (copy_from_user(dstbuf, buf, size)) - return -EFAULT; + return 0; if (dent == phba->debug_InjErrLBA) { - if ((buf[0] == 'o') && (buf[1] == 'f') && (buf[2] == 'f')) + if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && + (dstbuf[2] == 'f')) tmp = (uint64_t)(-1); } if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) - return -EINVAL; + return 0; if (dent == phba->debug_writeGuard) phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; @@ -2301,6 +2680,48 @@ out: return rc; } +/** + * lpfc_debugfs_ediflist_open - Open the ediflist debugfs file + * @inode: The inode pointer that contains a vport pointer. + * @file: The file pointer to attach the log output. + * + * Description: + * This routine is the entry point for the debugfs open file operation. It gets + * the vport from the i_private field in @inode, allocates the necessary buffer + * for the log, fills the buffer from the in-memory log for this vport, and then + * returns a pointer to that log in the private_data field in @file. + * + * Returns: + * This function returns zero if successful. On error it will return an negative + * error value. + **/ +static int +lpfc_debugfs_ediflist_open(struct inode *inode, struct file *file) +{ + struct lpfc_vport *vport = inode->i_private; + struct lpfc_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + /* Round to page boundary */ + debug->buffer = kmalloc(LPFC_EDIFLIST_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->len = lpfc_debugfs_ediflist_data(vport, debug->buffer, + LPFC_EDIFLIST_SIZE); + file->private_data = debug; + + rc = 0; +out: + return rc; +} + /** * lpfc_debugfs_lseek - Seek through a debugfs file * @file: The file pointer to seek through. @@ -2321,8 +2742,22 @@ out: static loff_t lpfc_debugfs_lseek(struct file *file, loff_t off, int whence) { - struct lpfc_debug *debug = file->private_data; - return fixed_size_llseek(file, off, whence, debug->len); + struct lpfc_debug *debug; + loff_t pos = -1; + + debug = file->private_data; + + switch (whence) { + case 0: + pos = off; + break; + case 1: + pos = file->f_pos + off; + break; + case 2: + pos = debug->len + off; + } + return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos); } /** @@ -2374,76 +2809,6 @@ lpfc_debugfs_release(struct inode *inode, struct file *file) return 0; } -/** - * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine clears multi-XRI pools statistics when buf contains "clear". - * - * Return Value: - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - char mybuf[64]; - char *pbuf; - u32 i; - u32 hwq_count; - struct lpfc_sli4_hdw_queue *qp; - struct lpfc_multixri_pool *multixri_pool; - - if (nbytes > 64) - nbytes = 64; - - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; - - memset(mybuf, 0, sizeof(mybuf)); - - if (copy_from_user(mybuf, buf, nbytes)) - return -EFAULT; - pbuf = &mybuf[0]; - - if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) { - hwq_count = phba->cfg_hdw_queue; - for (i = 0; i < hwq_count; i++) { - qp = &phba->sli4_hba.hdwq[i]; - multixri_pool = qp->p_multixri_pool; - if (!multixri_pool) - continue; - - qp->empty_io_bufs = 0; - multixri_pool->pbl_empty_count = 0; -#ifdef LPFC_MXP_STAT - multixri_pool->above_limit_count = 0; - multixri_pool->below_limit_count = 0; - multixri_pool->stat_max_hwm = 0; - multixri_pool->local_pbl_hit_count = 0; - multixri_pool->other_pbl_hit_count = 0; - - multixri_pool->stat_pbl_count = 0; - multixri_pool->stat_pvt_count = 0; - multixri_pool->stat_busy_count = 0; - multixri_pool->stat_snapshot_taken = 0; -#endif - } - return strlen(pbuf); - } - - return -EINVAL; -} - static int lpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file) { @@ -2477,6 +2842,7 @@ static ssize_t lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_debug *debug = file->private_data; struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; struct lpfc_hba *phba = vport->phba; @@ -2529,6 +2895,7 @@ lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf, atomic_set(&tgtp->xmt_abort_rsp, 0); atomic_set(&tgtp->xmt_abort_rsp_error, 0); } +#endif return nbytes; } @@ -2571,10 +2938,6 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf, char mybuf[6] = {0}; int i; - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; - if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ? (sizeof(mybuf) - 1) : nbytes)) return -EFAULT; @@ -2591,7 +2954,7 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf, } static int -lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file) +lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file) { struct lpfc_vport *vport = inode->i_private; struct lpfc_debug *debug; @@ -2602,14 +2965,14 @@ lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file) goto out; /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_NVMEKTIME_SIZE, GFP_KERNEL); + debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_nvmektime_data(vport, debug->buffer, - LPFC_NVMEKTIME_SIZE); + debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer, + LPFC_IOKTIME_SIZE); debug->i_private = inode->i_private; file->private_data = debug; @@ -2620,8 +2983,8 @@ out: } static ssize_t -lpfc_debugfs_nvmektime_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) +lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) { struct lpfc_debug *debug = file->private_data; struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; @@ -2807,7 +3170,7 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, kfree(phba->nvmeio_trc); /* Allocate new trace buffer and initialize */ - phba->nvmeio_trc = kzalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) * + phba->nvmeio_trc = kmalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) * sz), GFP_KERNEL); if (!phba->nvmeio_trc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -2815,6 +3178,8 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, "nvmeio_trc buffer\n"); return -ENOMEM; } + memset(phba->nvmeio_trc, 0, + (sizeof(struct lpfc_debugfs_nvmeio_trc) * sz)); atomic_set(&phba->nvmeio_trc_cnt, 0); phba->nvmeio_trc_on = 0; phba->nvmeio_trc_output_idx = 0; @@ -2823,7 +3188,7 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, } static int -lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file) +lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file) { struct lpfc_vport *vport = inode->i_private; struct lpfc_debug *debug; @@ -2834,14 +3199,14 @@ lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file) goto out; /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_CPUCHECK_SIZE, GFP_KERNEL); + debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_cpucheck_data(vport, debug->buffer, - LPFC_CPUCHECK_SIZE); + debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer, + LPFC_SCSISTAT_SIZE); debug->i_private = inode->i_private; file->private_data = debug; @@ -2852,16 +3217,16 @@ out: } static ssize_t -lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf, +lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { struct lpfc_debug *debug = file->private_data; struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; struct lpfc_hba *phba = vport->phba; - struct lpfc_sli4_hdw_queue *qp; + struct lpfc_hdwq_stat *c_stat; char mybuf[64]; char *pbuf; - int i, j; + int i; if (nbytes > 64) nbytes = 64; @@ -2874,41 +3239,39 @@ lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf, if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) { if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; else - phba->cpucheck_on |= (LPFC_CHECK_NVME_IO | + phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO | LPFC_CHECK_SCSI_IO); return strlen(pbuf); } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) { if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; else - phba->cpucheck_on |= LPFC_CHECK_NVME_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVME_IO; return strlen(pbuf); } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) { - phba->cpucheck_on |= LPFC_CHECK_SCSI_IO; + if (!phba->nvmet_support) + phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO; return strlen(pbuf); - } else if ((strncmp(pbuf, "rcv", - sizeof("rcv") - 1) == 0)) { - if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_RCV; - else - return -EINVAL; + } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) { + phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO | + LPFC_CHECK_NVMET_IO); + return strlen(pbuf); + } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) { + phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO; return strlen(pbuf); } else if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) { - phba->cpucheck_on = LPFC_CHECK_OFF; + phba->hdwqstat_on = LPFC_CHECK_OFF; return strlen(pbuf); } else if ((strncmp(pbuf, "zero", sizeof("zero") - 1) == 0)) { - for (i = 0; i < phba->cfg_hdw_queue; i++) { - qp = &phba->sli4_hba.hdwq[i]; - - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { - qp->cpucheck_rcv_io[j] = 0; - qp->cpucheck_xmt_io[j] = 0; - qp->cpucheck_cmpl_io[j] = 0; - } + for_each_present_cpu(i) { + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i); + c_stat->xmt_io = 0; + c_stat->cmpl_io = 0; + c_stat->rcv_io = 0; } return strlen(pbuf); } @@ -3129,17 +3492,17 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, switch (count) { case SIZE_U8: /* byte (8 bits) */ pci_read_config_byte(pdev, where, &u8val); - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "%03x: %02x\n", where, u8val); break; case SIZE_U16: /* word (16 bits) */ pci_read_config_word(pdev, where, &u16val); - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "%03x: %04x\n", where, u16val); break; case SIZE_U32: /* double word (32 bits) */ pci_read_config_dword(pdev, where, &u32val); - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "%03x: %08x\n", where, u32val); break; case LPFC_PCI_CFG_BROWSE: /* browse all */ @@ -3159,25 +3522,25 @@ pcicfg_browse: offset = offset_label; /* Read PCI config space */ - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "%03x: ", offset_label); while (index > 0) { pci_read_config_dword(pdev, offset, &u32val); - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "%08x ", u32val); offset += sizeof(uint32_t); if (offset >= LPFC_PCI_CFG_SIZE) { - len += scnprintf(pbuffer+len, - LPFC_PCI_CFG_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, + LPFC_PCI_CFG_SIZE - len, "\n"); break; } index -= sizeof(uint32_t); if (!index) - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "\n"); else if (!(index % (8 * sizeof(uint32_t)))) { offset_label += (8 * sizeof(uint32_t)); - len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_CFG_SIZE - len, "\n%03x: ", offset_label); } } @@ -3448,7 +3811,7 @@ lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, if (acc_range == SINGLE_WORD) { offset_run = offset; u32val = readl(mem_mapped_bar + offset_run); - len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_BAR_RD_BUF_SIZE - len, "%05x: %08x\n", offset_run, u32val); } else goto baracc_browse; @@ -3462,36 +3825,36 @@ baracc_browse: offset_run = offset_label; /* Read PCI bar memory mapped space */ - len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_BAR_RD_BUF_SIZE - len, "%05x: ", offset_label); index = LPFC_PCI_BAR_RD_SIZE; while (index > 0) { u32val = readl(mem_mapped_bar + offset_run); - len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_PCI_BAR_RD_BUF_SIZE - len, "%08x ", u32val); offset_run += sizeof(uint32_t); if (acc_range == LPFC_PCI_BAR_BROWSE) { if (offset_run >= bar_size) { - len += scnprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, + LPFC_PCI_BAR_RD_BUF_SIZE - len, "\n"); break; } } else { if (offset_run >= offset + (acc_range * sizeof(uint32_t))) { - len += scnprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, + LPFC_PCI_BAR_RD_BUF_SIZE - len, "\n"); break; } } index -= sizeof(uint32_t); if (!index) - len += scnprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, + LPFC_PCI_BAR_RD_BUF_SIZE - len, "\n"); else if (!(index % (8 * sizeof(uint32_t)))) { offset_label += (8 * sizeof(uint32_t)); - len += scnprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer + len, + LPFC_PCI_BAR_RD_BUF_SIZE - len, "\n%05x: ", offset_label); } } @@ -3675,7 +4038,7 @@ __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype, qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->hba_index, qp->notify_interval); - len += scnprintf(pbuffer + len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); return len; } @@ -3719,8 +4082,7 @@ __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype, qp->entry_size, qp->host_index, qp->notify_interval, qp->max_proc_limit); - len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, - "\n"); + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); return len; } @@ -3817,8 +4179,7 @@ __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype, qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->notify_interval, qp->max_proc_limit, qp->chann); - len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, - "\n"); + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); return len; } @@ -3872,9 +4233,9 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->lpfc_idiag_last_eq = 0; len += scnprintf(pbuffer + len, - LPFC_QUE_INFO_GET_BUF_SIZE - len, - "HDWQ %d out of %d HBA HDWQs\n", - x, phba->cfg_hdw_queue); + LPFC_QUE_INFO_GET_BUF_SIZE - len, + "HDWQ %d out of %d HBA HDWQs\n", + x, phba->cfg_hdw_queue); /* Fast-path EQ */ qp = phba->sli4_hba.hdwq[x].hba_eq; @@ -3956,7 +4317,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); too_big: - len += scnprintf(pbuffer + len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n"); out: spin_unlock_irq(&phba->hbalock); @@ -4012,22 +4373,22 @@ lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, return 0; esize = pque->entry_size; - len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_QUE_ACC_BUF_SIZE - len, "QE-INDEX[%04d]:\n", index); offset = 0; pentry = lpfc_sli4_qe(pque, index); while (esize > 0) { - len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_QUE_ACC_BUF_SIZE - len, "%08x ", *pentry); pentry++; offset += sizeof(uint32_t); esize -= sizeof(uint32_t); if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) - len += scnprintf(pbuffer+len, - LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, + LPFC_QUE_ACC_BUF_SIZE - len, "\n"); } - len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer + len, LPFC_QUE_ACC_BUF_SIZE - len, "\n"); return len; } @@ -4208,17 +4569,6 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, idiag.ptr_private = phba->sli4_hba.els_cq; goto pass_check; } - /* NVME LS complete queue */ - if (phba->sli4_hba.nvmels_cq && - phba->sli4_hba.nvmels_cq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.nvmels_cq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.nvmels_cq; - goto pass_check; - } /* FCP complete queue */ if (phba->sli4_hba.hdwq) { for (qidx = 0; qidx < phba->cfg_hdw_queue; @@ -4263,17 +4613,6 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, idiag.ptr_private = phba->sli4_hba.els_wq; goto pass_check; } - /* NVME LS work queue */ - if (phba->sli4_hba.nvmels_wq && - phba->sli4_hba.nvmels_wq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.nvmels_wq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.nvmels_wq; - goto pass_check; - } if (phba->sli4_hba.hdwq) { /* FCP/SCSI work queue */ @@ -4290,7 +4629,6 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } } - goto error_out; break; case LPFC_IDIAG_RQ: @@ -4378,7 +4716,7 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, switch (drbregid) { case LPFC_DRB_EQ: - len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, "EQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.EQDBregaddr)); break; @@ -4388,17 +4726,17 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, readl(phba->sli4_hba.CQDBregaddr)); break; case LPFC_DRB_MQ: - len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, "MQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.MQDBregaddr)); break; case LPFC_DRB_WQ: - len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, "WQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.WQDBregaddr)); break; case LPFC_DRB_RQ: - len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, "RQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.RQDBregaddr)); break; @@ -4588,37 +4926,37 @@ lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, switch (ctlregid) { case LPFC_CTL_PORT_SEM: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "Port SemReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_SEM_OFFSET)); break; case LPFC_CTL_PORT_STA: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "Port StaReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_STA_OFFSET)); break; case LPFC_CTL_PORT_CTL: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "Port CtlReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_CTL_OFFSET)); break; case LPFC_CTL_PORT_ER1: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "Port Er1Reg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_ER1_OFFSET)); break; case LPFC_CTL_PORT_ER2: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "Port Er2Reg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_ER2_OFFSET)); break; case LPFC_CTL_PDEV_CTL: - len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_CTL_ACC_BUF_SIZE - len, "PDev CtlReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET)); @@ -4811,13 +5149,13 @@ lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_MBX_ACC_BUF_SIZE - len, "mbx_dump_map: 0x%08x\n", mbx_dump_map); - len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_MBX_ACC_BUF_SIZE - len, "mbx_dump_cnt: %04d\n", mbx_dump_cnt); - len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_MBX_ACC_BUF_SIZE - len, "mbx_word_cnt: %04d\n", mbx_word_cnt); - len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_MBX_ACC_BUF_SIZE - len, "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); return len; @@ -4966,35 +5304,35 @@ lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) { uint16_t ext_cnt, ext_size; - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\nAvailable Extents Information:\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tPort Available VPI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, &ext_cnt, &ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tPort Available VFI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, &ext_cnt, &ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tPort Available RPI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, &ext_cnt, &ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tPort Available XRI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, &ext_cnt, &ext_size); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Count %3d, Size %3d\n", ext_cnt, ext_size); return len; @@ -5018,55 +5356,55 @@ lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) uint16_t ext_cnt, ext_size; int rc; - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\nAllocated Extents Information:\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tHost Allocated VPI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, &ext_cnt, &ext_size); if (!rc) - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "N/A\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tHost Allocated VFI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, &ext_cnt, &ext_size); if (!rc) - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "N/A\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tHost Allocated RPI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, &ext_cnt, &ext_size); if (!rc) - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "N/A\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tHost Allocated XRI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, &ext_cnt, &ext_size); if (!rc) - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "N/A\n"); return len; @@ -5090,49 +5428,49 @@ lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) struct lpfc_rsrc_blks *rsrc_blks; int index; - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\nDriver Extents Information:\n"); - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tVPI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tVFI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, list) { - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tRPI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, list) { - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\tXRI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, list) { - len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer + len, LPFC_EXT_ACC_BUF_SIZE - len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); @@ -5237,6 +5575,180 @@ lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } +static int +lpfc_cgn_buffer_open(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->i_private = inode->i_private; + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static ssize_t +lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + char *buffer = debug->buffer; + uint32_t *ptr; + int cnt, len = 0; + + if (!phba->sli4_hba.pc_sli4_params.E2E_attr || !phba->cgn_i) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "E2E Congestion Mgmt is not supported\n"); + goto out; + } + ptr = (uint32_t *)phba->cgn_i->virt; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Congestion Buffer Header\n"); + /* Dump the first 32 bytes */ + cnt = 32; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "000: %08x %08x %08x %08x %08x %08x %08x %08x\n", + *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), + *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7)); + ptr += 8; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Congestion Buffer Data\n"); + while (cnt < sizeof(struct lpfc_cgn_info)) { + if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Truncated . . .\n"); + break; + } + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "%03x: %08x %08x %08x %08x " + "%08x %08x %08x %08x\n", + cnt, *ptr, *(ptr + 1), *(ptr + 2), + *(ptr + 3), *(ptr + 4), *(ptr + 5), + *(ptr + 6), *(ptr + 7)); + cnt += 32; + ptr += 8; + } +out: + return simple_read_from_buffer(buf, nbytes, ppos, buffer, len); +} + +int +lpfc_cgn_buffer_release(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + +static int +lpfc_rx_monitor_open(struct inode *inode, struct file *file) +{ + struct lpfc_rx_monitor_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + debug->buffer = vmalloc(MAX_DEBUGFS_RX_TABLE_SIZE); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->i_private = inode->i_private; + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static ssize_t +lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_rx_monitor_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + char *buffer = debug->buffer; + struct rxtable_entry *entry; + int i, len = 0, head, tail, last, start; + + head = atomic_read(&phba->rxtable_idx_head); + while (head == LPFC_RXMONITOR_TABLE_IN_USE) { + /* Table is getting updated */ + msleep(10); + head = atomic_read(&phba->rxtable_idx_head); + } + + tail = atomic_xchg(&phba->rxtable_idx_tail, head); + if (head == tail) { + len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len, + "Rxtable is empty\n"); + goto out; + } + last = (head > tail) ? head : LPFC_MAX_RXMONITOR_ENTRY; + start = tail; + + len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len, + " MaxBPI\t Total Data Cmd Total Data Cmpl" + " Latency(us) Avg IO Size\tMax IO Size IO cnt" + " Info BWutil(ms)\n"); +get_table: + for (i = start; i < last; i++) { + entry = &phba->rxtable[i]; + len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len, + "%3d:%12lld %12lld\t%12lld\t" + "%8lldus\t%8lld\t%10lld " + "%8d %2d %2d(%2d)\n", + i, entry->max_bytes_per_interval, + entry->total_bytes, + entry->rcv_bytes, + entry->avg_io_latency, + entry->avg_io_size, + entry->max_read_cnt, + entry->io_cnt, + entry->cmf_info, + entry->timer_utilization, + entry->timer_interval); + } + + if (head != last) { + start = 0; + last = head; + goto get_table; + } +out: + return simple_read_from_buffer(buf, nbytes, ppos, buffer, len); +} + +int +lpfc_rx_monitor_release(struct inode *inode, struct file *file) +{ + struct lpfc_rx_monitor_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + #undef lpfc_debugfs_op_disc_trc static const struct file_operations lpfc_debugfs_op_disc_trc = { .owner = THIS_MODULE, @@ -5255,6 +5767,15 @@ static const struct file_operations lpfc_debugfs_op_nodelist = { .release = lpfc_debugfs_release, }; +#undef lpfc_debugfs_op_ediflist +static const struct file_operations lpfc_debugfs_op_ediflist = { + .owner = THIS_MODULE, + .open = lpfc_debugfs_ediflist_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_debugfs_read, + .release = lpfc_debugfs_release, +}; + #undef lpfc_debugfs_op_multixripools static const struct file_operations lpfc_debugfs_op_multixripools = { .owner = THIS_MODULE, @@ -5324,13 +5845,13 @@ static const struct file_operations lpfc_debugfs_op_scsistat = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_nvmektime -static const struct file_operations lpfc_debugfs_op_nvmektime = { +#undef lpfc_debugfs_op_ioktime +static const struct file_operations lpfc_debugfs_op_ioktime = { .owner = THIS_MODULE, - .open = lpfc_debugfs_nvmektime_open, + .open = lpfc_debugfs_ioktime_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, - .write = lpfc_debugfs_nvmektime_write, + .write = lpfc_debugfs_ioktime_write, .release = lpfc_debugfs_release, }; @@ -5344,20 +5865,20 @@ static const struct file_operations lpfc_debugfs_op_nvmeio_trc = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_cpucheck -static const struct file_operations lpfc_debugfs_op_cpucheck = { +#undef lpfc_debugfs_op_hdwqstat +static const struct file_operations lpfc_debugfs_op_hdwqstat = { .owner = THIS_MODULE, - .open = lpfc_debugfs_cpucheck_open, + .open = lpfc_debugfs_hdwqstat_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, - .write = lpfc_debugfs_cpucheck_write, + .write = lpfc_debugfs_hdwqstat_write, .release = lpfc_debugfs_release, }; #undef lpfc_debugfs_op_dif_err static const struct file_operations lpfc_debugfs_op_dif_err = { .owner = THIS_MODULE, - .open = simple_open, + .open = lpfc_debugfs_dif_err_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_dif_err_read, .write = lpfc_debugfs_dif_err_write, @@ -5457,6 +5978,32 @@ static const struct file_operations lpfc_idiag_op_extAcc = { .release = lpfc_idiag_cmd_release, }; +#undef lpfc_cgn_buffer_op +static const struct file_operations lpfc_cgn_buffer_op = { + .owner = THIS_MODULE, + .open = lpfc_cgn_buffer_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_cgn_buffer_read, + .release = lpfc_cgn_buffer_release, +}; + +#undef lpfc_rx_monitor_op +static const struct file_operations lpfc_rx_monitor_op = { + .owner = THIS_MODULE, + .open = lpfc_rx_monitor_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_rx_monitor_read, + .release = lpfc_rx_monitor_release, +}; + +#undef lpfc_debugfs_ras_log +static const struct file_operations lpfc_debugfs_ras_log = { + .owner = THIS_MODULE, + .open = lpfc_debugfs_ras_log_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_debugfs_read, + .release = lpfc_debugfs_ras_log_release, +}; #endif /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command @@ -5538,11 +6085,12 @@ lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, if (i != 0) pr_err("%s\n", line_buf); len = 0; - len += scnprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%03d: ", i); } - len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%08x ", (uint32_t)*pword); pword++; } @@ -5605,11 +6153,12 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) pr_err("%s\n", line_buf); len = 0; memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += scnprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%03d: ", i); } - len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%08x ", ((uint32_t)*pword) & 0xffffffff); pword++; @@ -5628,19 +6177,19 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) pr_err("%s\n", line_buf); len = 0; memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += scnprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%03d: ", i); } for (j = 0; j < 4; j++) { - len += scnprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, "%02x", ((uint8_t)*pbyte) & 0xff); pbyte++; } - len += scnprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, " "); + len += scnprintf(line_buf + len, + LPFC_MBX_ACC_LBUF_SZ - len, " "); } if ((i - 1) % 8) pr_err("%s\n", line_buf); @@ -5681,6 +6230,11 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) if (!lpfc_debugfs_root) { lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL); atomic_set(&lpfc_debugfs_hba_count, 0); + if (!lpfc_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0408 Cannot create debugfs root\n"); + goto debug_failed; + } } if (!lpfc_debugfs_start_time) lpfc_debugfs_start_time = jiffies; @@ -5691,6 +6245,11 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) pport_setup = true; phba->hba_debugfs_root = debugfs_create_dir(name, lpfc_debugfs_root); + if (!phba->hba_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0412 Cannot create debugfs hba\n"); + goto debug_failed; + } atomic_inc(&lpfc_debugfs_hba_count); atomic_set(&phba->debugfs_vport_count, 0); @@ -5707,12 +6266,56 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } + /* E2E Congestion Info Buffer */ + snprintf(name, sizeof(name), "cgn_buffer"); + phba->debug_cgn_buffer = + debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_cgn_buffer_op); + if (!phba->debug_cgn_buffer) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6527 Cannot create debugfs" + " cgn_buffer\n"); + goto debug_failed; + } + + /* RX Monitor */ + snprintf(name, sizeof(name), "rx_monitor"); + phba->debug_rx_monitor = + debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_rx_monitor_op); + if (!phba->debug_rx_monitor) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6528 Cannot create debugfs" + " rx_monitor\n"); + goto debug_failed; + } + + /* RAS log */ + snprintf(name, sizeof(name), "ras_log"); + phba->debug_ras_log = + debugfs_create_file(name, 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_ras_log); + if (!phba->debug_ras_log) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6148 Cannot create debugfs" + " ras_log\n"); + goto debug_failed; + } + /* Setup hbqinfo */ snprintf(name, sizeof(name), "hbqinfo"); phba->debug_hbqinfo = debugfs_create_file(name, S_IFREG | 0644, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_hbqinfo); + if (!phba->debug_hbqinfo) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0411 Cant create debugfs hbqinfo\n"); + goto debug_failed; + } #ifdef LPFC_HDWQ_LOCK_STAT /* Setup lockstat */ @@ -5736,6 +6339,12 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dumpHBASlim); + if (!phba->debug_dumpHBASlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0413 Cannot create debugfs " + "dumpHBASlim\n"); + goto debug_failed; + } } else phba->debug_dumpHBASlim = NULL; @@ -5747,6 +6356,12 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dumpHostSlim); + if (!phba->debug_dumpHostSlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0414 Cannot create debugfs " + "dumpHostSlim\n"); + goto debug_failed; + } } else phba->debug_dumpHostSlim = NULL; @@ -5756,6 +6371,11 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_InjErrLBA) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0807 Cannot create debugfs InjErrLBA\n"); + goto debug_failed; + } phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; snprintf(name, sizeof(name), "InjErrNPortID"); @@ -5763,48 +6383,88 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_InjErrNPortID) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0809 Cannot create debugfs InjErrNPortID\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "InjErrWWPN"); phba->debug_InjErrWWPN = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_InjErrWWPN) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0810 Cannot create debugfs InjErrWWPN\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "writeGuardInjErr"); phba->debug_writeGuard = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_writeGuard) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0802 Cannot create debugfs writeGuard\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "writeAppInjErr"); phba->debug_writeApp = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_writeApp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0803 Cannot create debugfs writeApp\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "writeRefInjErr"); phba->debug_writeRef = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_writeRef) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0804 Cannot create debugfs writeRef\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "readGuardInjErr"); phba->debug_readGuard = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_readGuard) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0808 Cannot create debugfs readGuard\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "readAppInjErr"); phba->debug_readApp = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_readApp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0805 Cannot create debugfs readApp\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "readRefInjErr"); phba->debug_readRef = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_readRef) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0806 Cannot create debugfs readApp\n"); + goto debug_failed; + } /* Setup slow ring trace */ if (lpfc_debugfs_max_slow_ring_trc) { @@ -5828,6 +6488,12 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_slow_ring_trc); + if (!phba->debug_slow_ring_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0415 Cannot create debugfs " + "slow_ring_trace\n"); + goto debug_failed; + } if (!phba->slow_ring_trc) { phba->slow_ring_trc = kmalloc( (sizeof(struct lpfc_debugfs_trc) * @@ -5845,11 +6511,17 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) lpfc_debugfs_max_slow_ring_trc)); } +#ifdef BUILD_NVME snprintf(name, sizeof(name), "nvmeio_trc"); phba->debug_nvmeio_trc = debugfs_create_file(name, 0644, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_nvmeio_trc); + if (!phba->debug_nvmeio_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0574 No create debugfs nvmeio_trc\n"); + goto debug_failed; + } atomic_set(&phba->nvmeio_trc_cnt, 0); if (lpfc_debugfs_max_nvmeio_trc) { @@ -5871,7 +6543,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc; /* Allocate trace buffer and initialize */ - phba->nvmeio_trc = kzalloc( + phba->nvmeio_trc = kmalloc( (sizeof(struct lpfc_debugfs_nvmeio_trc) * phba->nvmeio_trc_size), GFP_KERNEL); @@ -5881,6 +6553,9 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) "nvmeio_trc buffer\n"); goto nvmeio_off; } + memset(phba->nvmeio_trc, 0, + (sizeof(struct lpfc_debugfs_nvmeio_trc) * + phba->nvmeio_trc_size)); phba->nvmeio_trc_on = 1; phba->nvmeio_trc_output_idx = 0; phba->nvmeio_trc = NULL; @@ -5891,12 +6566,18 @@ nvmeio_off: phba->nvmeio_trc_output_idx = 0; phba->nvmeio_trc = NULL; } +#endif } snprintf(name, sizeof(name), "vport%d", vport->vpi); if (!vport->vport_debugfs_root) { vport->vport_debugfs_root = debugfs_create_dir(name, phba->hba_debugfs_root); + if (!vport->vport_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0417 Can't create debugfs\n"); + goto debug_failed; + } atomic_inc(&phba->debugfs_vport_count); } @@ -5933,17 +6614,43 @@ nvmeio_off: debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, vport->vport_debugfs_root, vport, &lpfc_debugfs_op_disc_trc); + if (!vport->debug_disc_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0419 Cannot create debugfs " + "discovery_trace\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "nodelist"); vport->debug_nodelist = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, vport->vport_debugfs_root, vport, &lpfc_debugfs_op_nodelist); + if (!vport->debug_nodelist) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2985 Can't create debugfs nodelist\n"); + goto debug_failed; + } + snprintf(name, sizeof(name), "ediflist"); + vport->debug_ediflist = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_ediflist); + if (!vport->debug_ediflist) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2987 Can't create debugfs ediflist\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "nvmestat"); vport->debug_nvmestat = debugfs_create_file(name, 0644, vport->vport_debugfs_root, vport, &lpfc_debugfs_op_nvmestat); + if (!vport->debug_nvmestat) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0811 Cannot create debugfs nvmestat\n"); + goto debug_failed; + } snprintf(name, sizeof(name), "scsistat"); vport->debug_scsistat = @@ -5956,17 +6663,27 @@ nvmeio_off: goto debug_failed; } - snprintf(name, sizeof(name), "nvmektime"); - vport->debug_nvmektime = + snprintf(name, sizeof(name), "ioktime"); + vport->debug_ioktime = debugfs_create_file(name, 0644, vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_nvmektime); + vport, &lpfc_debugfs_op_ioktime); + if (!vport->debug_ioktime) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0815 Cannot create debugfs ioktime\n"); + goto debug_failed; + } - snprintf(name, sizeof(name), "cpucheck"); - vport->debug_cpucheck = + snprintf(name, sizeof(name), "hdwqstat"); + vport->debug_hdwqstat = debugfs_create_file(name, 0644, vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_cpucheck); + vport, &lpfc_debugfs_op_hdwqstat); + if (!vport->debug_hdwqstat) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0819 Cannot create debugfs hdwqstat\n"); + goto debug_failed; + } /* * The following section is for additional directories/files for the @@ -5986,6 +6703,11 @@ nvmeio_off: if (!phba->idiag_root) { phba->idiag_root = debugfs_create_dir(name, phba->hba_debugfs_root); + if (!phba->idiag_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2922 Can't create idiag debugfs\n"); + goto debug_failed; + } /* Initialize iDiag data structure */ memset(&idiag, 0, sizeof(idiag)); } @@ -5996,6 +6718,11 @@ nvmeio_off: phba->idiag_pci_cfg = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_pciCfg); + if (!phba->idiag_pci_cfg) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2923 Can't create idiag debugfs\n"); + goto debug_failed; + } idiag.offset.last_rd = 0; } @@ -6005,6 +6732,11 @@ nvmeio_off: phba->idiag_bar_acc = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_barAcc); + if (!phba->idiag_bar_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3056 Can't create idiag debugfs\n"); + goto debug_failed; + } idiag.offset.last_rd = 0; } @@ -6014,6 +6746,11 @@ nvmeio_off: phba->idiag_que_info = debugfs_create_file(name, S_IFREG|S_IRUGO, phba->idiag_root, phba, &lpfc_idiag_op_queInfo); + if (!phba->idiag_que_info) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2924 Can't create idiag debugfs\n"); + goto debug_failed; + } } /* iDiag access PCI function queue */ @@ -6022,6 +6759,11 @@ nvmeio_off: phba->idiag_que_acc = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_queAcc); + if (!phba->idiag_que_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2926 Can't create idiag debugfs\n"); + goto debug_failed; + } } /* iDiag access PCI function doorbell registers */ @@ -6030,6 +6772,11 @@ nvmeio_off: phba->idiag_drb_acc = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); + if (!phba->idiag_drb_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2927 Can't create idiag debugfs\n"); + goto debug_failed; + } } /* iDiag access PCI function control registers */ @@ -6038,6 +6785,11 @@ nvmeio_off: phba->idiag_ctl_acc = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); + if (!phba->idiag_ctl_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2981 Can't create idiag debugfs\n"); + goto debug_failed; + } } /* iDiag access mbox commands */ @@ -6046,6 +6798,11 @@ nvmeio_off: phba->idiag_mbx_acc = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); + if (!phba->idiag_mbx_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2980 Can't create idiag debugfs\n"); + goto debug_failed; + } } /* iDiag extents access commands */ @@ -6057,6 +6814,12 @@ nvmeio_off: S_IFREG|S_IRUGO|S_IWUSR, phba->idiag_root, phba, &lpfc_idiag_op_extAcc); + if (!phba->idiag_ext_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2986 Cant create " + "idiag debugfs\n"); + goto debug_failed; + } } } @@ -6082,8 +6845,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) #ifdef CONFIG_SCSI_LPFC_DEBUG_FS struct lpfc_hba *phba = vport->phba; - kfree(vport->disc_trc); - vport->disc_trc = NULL; + if (vport->disc_trc) { + kfree(vport->disc_trc); + vport->disc_trc = NULL; + } + + debugfs_remove(vport->debug_ediflist); /* ediflist */ + vport->debug_ediflist = NULL; debugfs_remove(vport->debug_disc_trc); /* discovery_trace */ vport->debug_disc_trc = NULL; @@ -6097,11 +6865,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(vport->debug_scsistat); /* scsistat */ vport->debug_scsistat = NULL; - debugfs_remove(vport->debug_nvmektime); /* nvmektime */ - vport->debug_nvmektime = NULL; + debugfs_remove(vport->debug_ioktime); /* ioktime */ + vport->debug_ioktime = NULL; - debugfs_remove(vport->debug_cpucheck); /* cpucheck */ - vport->debug_cpucheck = NULL; + debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */ + vport->debug_hdwqstat = NULL; if (vport->vport_debugfs_root) { debugfs_remove(vport->vport_debugfs_root); /* vportX */ @@ -6117,6 +6885,15 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ phba->debug_hbqinfo = NULL; + debugfs_remove(phba->debug_cgn_buffer); + phba->debug_cgn_buffer = NULL; + + debugfs_remove(phba->debug_rx_monitor); + phba->debug_rx_monitor = NULL; + + debugfs_remove(phba->debug_ras_log); + phba->debug_ras_log = NULL; + #ifdef LPFC_HDWQ_LOCK_STAT debugfs_remove(phba->debug_lockstat); /* lockstat */ phba->debug_lockstat = NULL; @@ -6154,8 +6931,10 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_readRef); /* readRef */ phba->debug_readRef = NULL; - kfree(phba->slow_ring_trc); - phba->slow_ring_trc = NULL; + if (phba->slow_ring_trc) { + kfree(phba->slow_ring_trc); + phba->slow_ring_trc = NULL; + } /* slow_ring_trace */ debugfs_remove(phba->debug_slow_ring_trc); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 20f2537af..c89c2c4f2 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -32,6 +32,10 @@ #define LPFC_NODELIST_SIZE 8192 #define LPFC_NODELIST_ENTRY_SIZE 120 +/* ediflist output buffer size */ +#define LPFC_EDIFLIST_SIZE 8192 +#define LPFC_EDIFLIST_ENTRY_SIZE 120 + /* dumpHBASlim output buffer size */ #define LPFC_DUMPHBASLIM_SIZE 4096 @@ -44,15 +48,27 @@ /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 +/* multixripool output buffer size */ +#define LPFC_DUMP_MULTIXRIPOOL_SIZE 8192 + +enum { + DUMP_IO, + DUMP_MBX, + DUMP_ELS, + DUMP_NVMELS, +}; + /* nvmestat output buffer size */ #define LPFC_NVMESTAT_SIZE 8192 -#define LPFC_NVMEKTIME_SIZE 8192 -#define LPFC_CPUCHECK_SIZE 8192 +#define LPFC_IOKTIME_SIZE 8192 #define LPFC_NVMEIO_TRC_SIZE 8192 /* scsistat output buffer size */ #define LPFC_SCSISTAT_SIZE 8192 +/* E2E Congestion Info Buffer size */ +#define LPFC_CGN_BUF_SIZE 8192 + #define LPFC_DEBUG_OUT_LINE_SZ 80 /* @@ -279,22 +295,12 @@ struct lpfc_idiag { struct lpfc_idiag_offset offset; void *ptr_private; }; - -#else - -#define lpfc_nvmeio_data(phba, fmt, arg...) \ - no_printk(fmt, ##arg) - #endif -/* multixripool output buffer size */ -#define LPFC_DUMP_MULTIXRIPOOL_SIZE 8192 - -enum { - DUMP_IO, - DUMP_MBX, - DUMP_ELS, - DUMP_NVMELS, +#define MAX_DEBUGFS_RX_TABLE_SIZE (100 * LPFC_MAX_RXMONITOR_ENTRY) +struct lpfc_rx_monitor_debug { + char *i_private; + char *buffer; }; /* Mask for discovery_trace */ diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 482e4a888..34ce065d0 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -41,6 +41,10 @@ enum lpfc_work_type { LPFC_EVT_DEV_LOSS, LPFC_EVT_FASTPATH_MGMT_EVT, LPFC_EVT_RESET_HBA, +#ifndef BUILD_BRCMFCOE + LPFC_EVT_REAUTH, +#endif + LPFC_EVT_RECOVER_PORT }; /* structure used to queue event to the discovery tasklet */ @@ -76,8 +80,46 @@ struct lpfc_node_rrqs { unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; }; +struct throttle_history { + /* Throttle log defaults if more than 10 messages per second */ + #define ONE_SEC 1000000 /* one second */ + bool logit; /* True means throttle logging on */ + uint32_t log_messages_lost; /* Messages discarded due to throttle */ + uint32_t log_messages; /* Log messages count within second */ + uint64_t log_start; /* start of message burst in usec */ + char announcement[16]; /* announcement string */ +}; + +struct dhchap_config { + uint16_t auth_tmo; + uint8_t auth_mode; + uint8_t bidirectional; + uint32_t tran_id; + uint32_t hash_id; + uint32_t dh_grp_id; + uint32_t reauth_interval; + uint8_t local_passwd[128]; + uint32_t local_passwd_len; + uint8_t remote_passwd[128]; + uint32_t remote_passwd_len; + uint8_t state; + uint8_t msg; + uint8_t direction; + uint8_t dh_grp_cnt; + uint8_t hash_pri[4]; + uint8_t dh_grp_pri[8]; + uint8_t rand_num[20]; + uint8_t nonce[16]; + uint8_t dhkey[256]; + uint32_t dhkey_len; + unsigned long last_auth; + struct timer_list nlp_reauthfunc; +}; + struct lpfc_nodelist { struct list_head nlp_listp; + struct throttle_history log; /* used to record throttle */ + struct serv_parm fc_sparam; /* buffer for service params */ struct lpfc_name nlp_portname; struct lpfc_name nlp_nodename; uint32_t nlp_flag; /* entry flags */ @@ -115,6 +157,7 @@ struct lpfc_nodelist { u8 nlp_nvme_info; /* NVME NSLER Support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ + uint32_t first_burst; /* First Burst size for ndlp */ uint16_t nlp_usg_map; /* ndlp management usage bitmap */ #define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ #define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ @@ -128,19 +171,28 @@ struct lpfc_nodelist { struct lpfc_vport *vport; struct lpfc_work_evt els_retry_evt; struct lpfc_work_evt dev_loss_evt; + struct lpfc_work_evt reauth_evt; + struct lpfc_work_evt recovery_evt; struct kref kref; atomic_t cmd_pending; uint32_t cmd_qdepth; +#ifndef NO_APEX +#define MAX_FCP_PRI_LUN 256 + uint8_t fcp_priority[MAX_FCP_PRI_LUN]; /* 512 lun priority */ +#endif unsigned long last_change_time; unsigned long *active_rrqs_xri_bitmap; struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ uint32_t fc4_prli_sent; uint32_t upcall_flags; #define NLP_WAIT_FOR_UNREG 0x1 +#define NLP_WAIT_FOR_LOGO 0x2 uint32_t nvme_fb_size; /* NVME target's supported byte cnt */ #define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */ + struct dhchap_config dhc_cfg; uint32_t nlp_defer_did; + wait_queue_head_t *logo_waitq; }; struct lpfc_node_rrq { struct list_head list; @@ -159,7 +211,8 @@ struct lpfc_node_rrq { /* Defines for nlp_flag (uint32) */ #define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */ #define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */ -#define NLP_RELEASE_RPI 0x00000004 /* Release RPI to free pool */ +#define NLP_SKIP_EXT_DIF 0x00000004 /* Target could support External DIF */ +#define NLP_RELEASE_RPI 0x00000008 /* Release RPI to free pool */ #define NLP_SUPPRESS_RSP 0x00000010 /* Remote NPort supports suppress rsp */ #define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ #define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ @@ -169,6 +222,7 @@ struct lpfc_node_rrq { #define NLP_ELS_SND_MASK 0x000007e0 /* sent ELS request for this entry */ #define NLP_NVMET_RECOV 0x00001000 /* NVMET auditing node for recovery. */ #define NLP_FCP_PRLI_RJT 0x00002000 /* Rport does not support FCP PRLI. */ +#define NLP_AUTH_TMO 0x00004000 /* authentication timer is active */ #define NLP_UNREG_INP 0x00008000 /* UNREG_RPI cmd is in progress */ #define NLP_DEFER_RM 0x00010000 /* Remove this ndlp if no longer used */ #define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ @@ -185,7 +239,7 @@ struct lpfc_node_rrq { #define NLP_RM_DFLT_RPI 0x04000000 /* need to remove leftover dflt RPI */ #define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ -#define NLP_SC_REQ 0x20000000 /* Target requires authentication */ +#define NLP_EXTERNAL_DIF 0x20000000 /* Target could support External DIF */ #define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */ #define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4e994a693..10c491b0d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -55,8 +55,12 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry); static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb); +static void +lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); static int lpfc_max_els_tries = 3; +extern int lpfc_fabric_cgn_frequency; /** * lpfc_els_chk_latt - Check host link attention event for a vport @@ -100,7 +104,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) return 0; /* Pending Link Event during Discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0237 Pending Link Event during " "Discovery: State x%x\n", phba->pport->port_state); @@ -440,8 +444,9 @@ fail_free_mbox: fail: lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login: Err %d\n", err); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0249 Cannot issue Register Fabric login: Err %d\n", + err); return -ENXIO; } @@ -524,8 +529,8 @@ fail: } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0289 Issue Register VFI failed: Err %d\n", rc); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0289 Issue Register VFI failed: Err %d\n", rc); return rc; } @@ -550,7 +555,7 @@ lpfc_issue_unreg_vfi(struct lpfc_vport *vport) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2556 UNREG_VFI mbox allocation failed" "HBA state x%x\n", phba->pport->port_state); return -ENOMEM; @@ -562,7 +567,7 @@ lpfc_issue_unreg_vfi(struct lpfc_vport *vport) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2557 UNREG_VFI issue mbox failed rc x%x " "HBA state x%x\n", rc, phba->pport->port_state); @@ -1041,18 +1046,18 @@ stop_rr_fcf_flogi: if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == IOERR_LOOP_OPEN_FAILURE))) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x " - "TMO:x%x Data x%x x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, phba->hba_flag, - phba->fcf.fcf_flag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2858 FLOGI failure Status:x%x/x%x TMO" + ":x%x Data x%x x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout, phba->hba_flag, + phba->fcf.fcf_flag); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT, "0150 FLOGI failure Status:x%x/x%x " "xri x%x TMO:x%x\n", irsp->ulpStatus, irsp->un.ulpWord[4], @@ -1061,8 +1066,15 @@ stop_rr_fcf_flogi: /* If this is not a loop open failure, bail out */ if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == - IOERR_LOOP_OPEN_FAILURE))) + IOERR_LOOP_OPEN_FAILURE))) { + /* FLOGI failure */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0100 FLOGI failure Status:x%x/x%x " + "TMO:x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout); goto flogifail; + } /* FLOGI failed, so there is no fabric */ spin_lock_irq(shost->host_lock); @@ -1132,8 +1144,7 @@ stop_rr_fcf_flogi: else if (!(phba->hba_flag & HBA_FCOE_MODE)) rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp); else { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_FIP | LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2831 FLOGI response with cleared Fabric " "bit fcf_index 0x%x " "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x " @@ -1314,6 +1325,9 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Can't do SLI4 class2 without support sequence coalescing */ sp->cls2.classValid = 0; sp->cls2.seqDelivery = 0; + + if (phba->cfg_enable_auth) + sp->cmn.fcsp = 1; } else { /* Historical, setting sequential-delivery bit for SLI3 */ sp->cls2.seqDelivery = (sp->cls2.classValid) ? 1 : 0; @@ -1426,6 +1440,9 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) lpfc_sli_issue_abort_iotag(phba, pring, iocb); } } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + spin_unlock_irq(&phba->hbalock); return 0; @@ -1473,6 +1490,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport) return 0; } + /* Reset the Fabric flag; topology change may have happened */ + vport->fc_flag &= ~FC_FABRIC; if (lpfc_issue_els_flogi(vport, ndlp, 0)) { /* This decrement of reference count to node shall kick off * the release of the node. @@ -1748,7 +1767,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, keep_nlp_state = new_ndlp->nlp_state; lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); - /* interchange the nvme remoteport structs */ + /* For nvme, swap the nrport. */ keep_nrport = new_ndlp->nrport; new_ndlp->nrport = ndlp->nrport; @@ -1934,7 +1953,7 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2882 RRQ completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", irsp->un.elsreq64.remoteID, @@ -1957,10 +1976,11 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2881 RRQ failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2881 RRQ failure DID:%06X Status:" + "x%x/x%x\n", + ndlp->nlp_DID, irsp->ulpStatus, + irsp->un.ulpWord[4]); } out: if (rrq) @@ -2010,7 +2030,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0136 PLOGI completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", irsp->un.elsreq64.remoteID, @@ -2059,7 +2079,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2753 PLOGI failure DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); @@ -2237,6 +2257,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; char *mode; + u32 loglevel; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2278,13 +2299,16 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * could be expected. */ if ((vport->fc_flag & FC_FABRIC) || - (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) + (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) { mode = KERN_ERR; - else + loglevel = LOG_TRACE_EVENT; + } else { mode = KERN_INFO; + loglevel = LOG_ELS; + } /* PRLI failed */ - lpfc_printf_vlog(vport, mode, LOG_ELS, + lpfc_printf_vlog(vport, mode, loglevel, "2754 PRLI failure DID:%06X Status:x%x/x%x, " "data: x%x\n", ndlp->nlp_DID, irsp->ulpStatus, @@ -2425,7 +2449,9 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } npr->estabImagePair = 1; npr->readXferRdyDis = 1; - if (vport->cfg_first_burst_size) + if (phba->sli_rev == LPFC_SLI_REV4 && + !(phba->hba_flag & HBA_FCOE_MODE) && + vport->cfg_first_burst_size) npr->writeXferRdyDis = 1; /* For FCP support */ @@ -2477,25 +2503,22 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_stat.elsXmitPRLI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_PRLI_SND; + + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } /* The vport counters are used for lpfc_scan_finished, but * the ndlp is used to track outstanding PRLIs for different * FC4 types. */ + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_PRLI_SND; vport->fc_prli_sent++; ndlp->fc4_prli_sent++; spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - /* The driver supports 2 FC4 types. Make sure * a PRLI is issued for all types before exiting. @@ -2695,7 +2718,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } /* ADISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2755 ADISC failure DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); @@ -2806,9 +2829,9 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = ndlp->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfcMboxq *mbox; unsigned long flags; uint32_t skip_recovery = 0; + int wake_up_waiter = 0; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2816,6 +2839,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &(rspiocb->iocb); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_LOGO_SND; + if (ndlp->upcall_flags & NLP_WAIT_FOR_LOGO) { + wake_up_waiter = 1; + ndlp->upcall_flags &= ~NLP_WAIT_FOR_LOGO; + } spin_unlock_irq(shost->host_lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -2853,7 +2880,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if (irsp->ulpStatus) { /* LOGO failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2756 LOGO failure, No Retry DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); @@ -2869,32 +2896,15 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, out: lpfc_els_free_iocb(phba, cmdiocb); - /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */ - if ((vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_PT2PT_PLOGI)) { - phba->pport->fc_myDID = 0; - if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || - (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { - if (phba->nvmet_support) - lpfc_nvmet_update_targetport(phba); - else - lpfc_nvme_update_localport(phba->pport); - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == - MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - skip_recovery = 1; - } - } - } + /* At this point, the LOGO processing is complete. NOTE: For a + * pt2pt topology, we are assuming the NPortID will only change + * on link up processing. For a LOGO / PLOGI initiated by the + * Initiator, we are assuming the NPortID is not going to change. + */ + if (wake_up_waiter && ndlp->logo_waitq) + wake_up(ndlp->logo_waitq); /* * If the node is a target, the handling attempts to recover the port. * For any other port type, the rpi is unregistered as an implicit @@ -3008,10 +3018,9 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * This routine is a generic completion callback function for ELS commands. * Specifically, it is the callback function which does not need to perform * any command specific operations. It is currently used by the ELS command - * issuing routines for the ELS State Change Request (SCR), - * lpfc_issue_els_scr(), and the ELS Fibre Channel Address Resolution - * Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). Other than - * certain debug loggings, this callback function simply invokes the + * issuing routines for RSCN, lpfc_issue_els_rscn, and the ELS Fibre Channel + * Address Resolution Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). + * Other than certain debug loggings, this callback function simply invokes the * lpfc_els_chk_latt() routine to check whether link went down during the * discovery process. **/ @@ -3025,109 +3034,134 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "ELS cmd cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); + "ELS cmd cmpl: status:x%x/x%x did:x%x", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->un.elsreq64.remoteID); + /* ELS cmd tag completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n", irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout); + + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(vport); + lpfc_els_free_iocb(phba, cmdiocb); +} + +/** + * lpfc_cmpl_els_disc_cmd - Completion callback function for Discovery ELS cmd + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + * This routine is a generic completion callback function for Discovery ELS cmd. + * Currently used by the ELS command issuing routines for the ELS State Change + * Request (SCR), lpfc_issue_els_scr(), Exchange Diagnostic Capabilities (EDC), + * lpfc_issue_els_edc() and the ELS RDF, lpfc_issue_els_rdf(). + * These commands will be retried once only for ELS timeout errors. + **/ +static void +lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + IOCB_t *irsp; + struct lpfc_els_rdf_rsp *prdf; + struct lpfc_dmabuf *pcmd, *prsp; + u32 *pdata; + u32 cmd; + + irsp = &rspiocb->iocb; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "ELS cmd cmpl: status:x%x/x%x did:x%x", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->un.elsreq64.remoteID); + + /* ELS cmd tag completes */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "0217 ELS cmd tag x%x completes Data: x%x x%x x%x x%x\n", + irsp->ulpIoTag, irsp->ulpStatus, + irsp->un.ulpWord[4], irsp->ulpTimeout, + cmdiocb->retry); + + pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; + if (!pcmd) + goto out; + + pdata = (u32 *)pcmd->virt; + if (!pdata) + goto out; + cmd = *pdata; + + /* Only 1 retry for ELS Timeout only */ + if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_SEQUENCE_TIMEOUT)) { + cmdiocb->retry++; + if (cmdiocb->retry <= 1) { + switch (cmd) { + case ELS_CMD_SCR: + lpfc_issue_els_scr(vport, cmdiocb->retry); + break; + case ELS_CMD_EDC: + lpfc_issue_els_edc(vport, cmdiocb->retry); + break; + case ELS_CMD_RDF: + cmdiocb->context1 = NULL; /* save ndlp refcnt */ + lpfc_issue_els_rdf(vport, cmdiocb->retry); + break; + } + goto out; + } + phba->fc_stat.elsRetryExceeded++; + } + if (cmd == ELS_CMD_EDC) { + lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb); + return; + } + if (irsp->ulpStatus) { + /* ELS discovery cmd completes with error */ + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, + "4203 ELS cmd x%x error: x%x x%X\n", cmd, + irsp->ulpStatus, irsp->un.ulpWord[4]); + goto out; + } + + /* The RDF response doesn't have any impact on the running driver + * but the notification descriptors are dumped here for support. + */ + if (cmd == ELS_CMD_RDF) { + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + prdf = (struct lpfc_els_rdf_rsp *)prsp->virt; + if (!prdf) + goto out; + + lpfc_sli_bemem_bcopy(prdf, prdf, sizeof(*prdf)); + + /* ELS cmd tag completes */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4677 Fabric RDF Notification Grant Data: " + "%u 0x%08x 0x%08x 0x%08x 0x%08x Reg: %x %x\n", + prdf->rdf_desc.count, + prdf->rdf_desc.desc[0], + prdf->rdf_desc.desc[1], + prdf->rdf_desc.desc[2], + prdf->rdf_desc.desc[3], + phba->cgn_reg_signal, phba->cgn_reg_fpin); + } + + out: /* Check to see if link went down during discovery */ lpfc_els_chk_latt(vport); lpfc_els_free_iocb(phba, cmdiocb); return; } -/** - * lpfc_issue_els_scr - Issue a scr to an node on a vport - * @vport: pointer to a host virtual N_Port data structure. - * @nportid: N_Port identifier to the remote node. - * @retry: number of retries to the command IOCB. - * - * This routine issues a State Change Request (SCR) to a fabric node - * on a @vport. The remote node @nportid is passed into the function. It - * first search the @vport node list to find the matching ndlp. If no such - * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An - * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() - * routine is invoked to send the SCR IOCB. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the SCR ELS command. - * - * Return code - * 0 - Successfully issued scr command - * 1 - Failed to issue scr command - **/ -int -lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - struct lpfc_nodelist *ndlp; - - cmdsize = (sizeof(uint32_t) + sizeof(SCR)); - - ndlp = lpfc_findnode_did(vport, nportid); - if (!ndlp) { - ndlp = lpfc_nlp_init(vport, nportid); - if (!ndlp) - return 1; - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; - } - - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_SCR); - - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); - return 1; - } - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = ELS_CMD_SCR; - pcmd += sizeof(uint32_t); - - /* For SCR, remainder of payload is SCR parameter page */ - memset(pcmd, 0, sizeof(SCR)); - ((SCR *) pcmd)->Function = SCR_FUNC_FULL; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue SCR: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitSCR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - if (!(vport->fc_flag & FC_PT2PT)) - lpfc_nlp_put(ndlp); - return 0; -} - /** * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric) * or the other nport (pt2pt). @@ -3205,9 +3239,7 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) event->rscn.rscn_cmd = ELS_RSCN; event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page); event->rscn.rscn_plen = cpu_to_be16(cmdsize); - nportid = vport->fc_myDID; - /* appears that page flags must be 0 for fabric to broadcast RSCN */ event->portid.rscn_page_flags = 0; event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16; event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; @@ -3234,10 +3266,624 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) */ if (!(vport->fc_flag & FC_PT2PT)) lpfc_nlp_put(ndlp); - return 0; } +/** + * lpfc_issue_els_scr - Issue a scr to an node on a vport + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command IOCB. + * + * This routine issues a State Change Request (SCR) to a fabric node + * on a @vport. The remote node is Fabric Controller (0xfffffd). It + * first search the @vport node list to find the matching ndlp. If no such + * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An + * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() + * routine is invoked to send the SCR IOCB. + * + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp + * will be incremented by 1 for holding the ndlp and the reference to ndlp + * will be stored into the context1 field of the IOCB for the completion + * callback function to the SCR ELS command. + * + * Return code + * 0 - Successfully issued scr command + * 1 - Failed to issue scr command + **/ +int +lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + uint8_t *pcmd; + uint16_t cmdsize; + struct lpfc_nodelist *ndlp; + + cmdsize = (sizeof(uint32_t) + sizeof(SCR)); + + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); + if (!ndlp) { + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); + if (!ndlp) + return 1; + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 1; + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_SCR); + + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + return 1; + } + + pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + + *((uint32_t *) (pcmd)) = ELS_CMD_SCR; + pcmd += sizeof(uint32_t); + + /* For SCR, remainder of payload is SCR parameter page */ + memset(pcmd, 0, sizeof(SCR)); + ((SCR *) pcmd)->Function = SCR_FUNC_FULL; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue SCR: did:x%x", + ndlp->nlp_DID, 0, 0); + + phba->fc_stat.elsXmitSCR++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + /* Keep the ndlp just in case RDF is being sent */ + return 0; +} + +/** + * lpfc_issue_els_rdf - Register for diagnostic functions from the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command IOCB. + * + * This routine issues an ELS RDF to the Fabric Controller to register + * for diagnostic functions. + * + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp + * will be incremented by 1 for holding the ndlp and the reference to ndlp + * will be stored into the context1 field of the IOCB for the completion + * callback function to the SCR ELS command. + * + * Return code + * 0 - Successfully issued scr command + * 1 - Failed to issue scr command + **/ +int +lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_els_rdf_req *prdf; + uint16_t cmdsize; + struct lpfc_nodelist *ndlp; + + cmdsize = sizeof(struct lpfc_els_rdf_req); + + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); + if (!ndlp) { + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); + if (!ndlp) + return -ENODEV; + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return -ENODEV; + } + + /* RDF ELS is not required on an NPIV VN_Port. */ + if (vport->port_type == LPFC_NPIV_PORT) { + lpfc_nlp_put(ndlp); /* Cleanup ndlp from SCR */ + return -EACCES; + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_RDF); + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + return -ENOMEM; + } + + /* Configure the payload for the supported FPIN events. */ + prdf = (struct lpfc_els_rdf_req *) + (((struct lpfc_dmabuf *)elsiocb->context2)->virt); + memset(prdf, 0, cmdsize); + prdf->word0 = ELS_CMD_RDF; + + /* The desc_list_len is size of the supported descriptor + * payload (28 bytes). The rdf_desc_len is count + + * 4 notification descriptors. Driver sends all and only + * sets the supported type as nonzero. + */ + prdf->rdf_desc.rdf_desc_tag = cpu_to_be32(ELS_FPIN_REG); + + /* Set the default supported descriptors and assume an initial + * descriptor length. + */ + /* Use the default list, 4 descriptors */ + prdf->desc_list_len = cpu_to_be32(sizeof(struct rdf_desc)); + prdf->rdf_desc.rdf_desc_len = + cpu_to_be32(sizeof(struct rdf_desc) - 8); + prdf->rdf_desc.desc[0] = cpu_to_be32(FPIN_NOTIFY_LINK_INTEG); + prdf->rdf_desc.desc[1] = cpu_to_be32(FPIN_NOTIFY_DELIVERY); + prdf->rdf_desc.desc[2] = cpu_to_be32(FPIN_NOTIFY_PEER_CGN); + prdf->rdf_desc.desc[3] = cpu_to_be32(FPIN_NOTIFY_CGN); + prdf->rdf_desc.count = cpu_to_be32(LPFC_MAX_NUM_OF_FPIN_TYPES); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RDF: did:x%x", + ndlp->nlp_DID, 0, 0); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "6444 Xmit RDF to remote " + "NPORT x%x Reg: %x %x\n", + ndlp->nlp_DID, phba->cgn_reg_signal, + phba->cgn_reg_fpin); + + phba->cgn_fpin_frequency = LPFC_FPIN_INIT_FREQ; + phba->fc_stat.elsXmitRDF++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; + } + + /* An RDF was issued - this put ensures the ndlp is cleaned up + * when the RDF completes. + */ + lpfc_nlp_put(ndlp); + return 0; +} + +/** + * lpfc_least_capable_settings - helper function for EDC rsp processing + * @phba: pointer to lpfc hba data structure. + * @pcgndet: pointer to congestion detection descriptor in EDC rsp. + * + * This helper routine determines the least capable setting for + * congestion signals, signal freq, including scale, from the + * congestion detection descriptor in the EDC rsp. The routine + * sets @phba values in preparation for a set_featues mailbox. + **/ +static void +lpfc_least_capable_settings(struct lpfc_hba *phba, struct cgn_det_desc *pcgndet) +{ + u32 rsp_sig_cap = 0, drv_sig_cap = 0; + u32 rsp_sig_freq_cyc = 0, rsp_sig_freq_scale = 0; + struct lpfc_cgn_info *cp; + u32 crc; + u16 sig_freq; + + /* Get rsp signal and frequency capabilities. */ + rsp_sig_cap = bf_get(xmt_sig_cap, pcgndet); + rsp_sig_freq_cyc = bf_get(xmt_sig_freq_cyc, pcgndet); + rsp_sig_freq_scale = bf_get(xmt_sig_freq_scale, pcgndet); + + /* If the Fport does not support signals. Set FPIN only */ + if (rsp_sig_cap == XMT_SIG_CAP_NO_SPT) { + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = RCV_SIG_FREQ_CYC_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | + LPFC_CGN_FPIN_WARN; + return; + } + + /* Apply the xmt scale to the xmt cycle to get the correct frequency. + * Adapter default is 100 millisSeconds. Convert all xmt cycle values + * to milliSeconds. + */ + switch (rsp_sig_freq_scale) { + case RCV_SIG_FREQ_SCALE_SEC: + rsp_sig_freq_cyc *= MSEC_PER_SEC; + break; + case RCV_SIG_FREQ_SCALE_USEC: + case RCV_SIG_FREQ_SCALE_NSEC: + rsp_sig_freq_cyc = 1; + break; + case RCV_SIG_FREQ_SCALE_NO_SPT: + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = RCV_SIG_FREQ_CYC_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + return; + default: + /*milliSeconds - all good. */ + break; + } + + /* Convenient shorthand. */ + drv_sig_cap = phba->cgn_reg_signal; + + /* Choose the least capable frequency. */ + if (rsp_sig_freq_cyc > phba->cgn_sig_freq) + phba->cgn_sig_freq = rsp_sig_freq_cyc; + + /* Should be some common signals support. Settle on least capable + * signal and adjust FPIN values. Initialize defaults to ease the + * decision. + */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + if (rsp_sig_cap == XMT_SIG_CAP_WARN_SPT && + (drv_sig_cap == LPFC_CGN_SIGNAL_WARN || + drv_sig_cap == LPFC_CGN_SIGNAL_BOTH)) { + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_WARN; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + if (rsp_sig_cap == XMT_SIG_CAP_BOTH_SPT) { + if (drv_sig_cap == LPFC_CGN_SIGNAL_BOTH) { + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_BOTH; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_NONE; + } + if (drv_sig_cap == LPFC_CGN_SIGNAL_WARN) { + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_WARN; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + } + + if (!phba->cgn_i) + return; + + /* Update signal frequency in congestion info buffer */ + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + /* Frequency (in ms) Signal Warning/Signal Congestion Notifications + * are received by the HBA + */ + sig_freq = phba->cgn_sig_freq; + + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN) + cp->cgn_warn_freq = cpu_to_le16(sig_freq); + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + cp->cgn_alarm_freq = cpu_to_le16(sig_freq); + cp->cgn_warn_freq = cpu_to_le16(sig_freq); + } + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); +} + +/** + * lpfc_cmpl_els_edc - Completion callback function for EDC + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + * This routine is the completion callback function for issuing the Exchange + * Diagnostic Capabilities (EDC) command. The driver issues an EDC to + * notify the FPort of its Congestion and Link Fault capabilities. This + * routine parses the FPort's response and decides on the least common + * values applicable to both FPort and NPort for Warnings and Alarms that + * are communicated via hardware signals. + **/ +static void +lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + IOCB_t *irsp; + struct lpfc_els_edc_rsp *pedc; + struct cgn_det_desc *pcgndet; + struct link_flt_desc *plnkflt; + struct unknown_desc *punk; + struct lpfc_dmabuf *pcmd, *prsp; + u8 *payload, bytes; + u32 *pdata, desctag; + int desc_total_bytes; + bool rcv_cap_desc = false; + + irsp = &rspiocb->iocb; + + lpfc_debugfs_disc_trc(phba->pport, LPFC_DISC_TRC_ELS_CMD, + "EDC cmpl: status:x%x/x%x did:x%x", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->un.elsreq64.remoteID); + + /* ELS cmd tag completes */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4201 EDC cmd tag x%x completes Data: x%x x%x x%x\n", + irsp->ulpIoTag, irsp->ulpStatus, + irsp->un.ulpWord[4], irsp->ulpTimeout); + + pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; + if (!pcmd) + goto out; + + pdata = (u32 *)pcmd->virt; + if (!pdata) + goto out; + + /* Need to clear signal values, send features MB and RDF with FPIN. */ + if (irsp->ulpStatus) { + /* ELS cmd tag completes */ + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, + "4202 EDC rsp error - sending RDF " + "for FPIN only.\n"); + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = RCV_SIG_FREQ_CYC_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + goto rsp_err; + } + + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + pedc = (struct lpfc_els_edc_rsp *)prsp->virt; + if (!pedc) + goto out; + + lpfc_sli_bemem_bcopy(pedc, pedc, sizeof(*pedc)); + + /* ELS cmd tag completes */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4676 Fabric EDC Rsp Data: " + "0x%08x, 0x%08x, 0x%08x, 0x%08x 0x%08x\n", + pedc->word0, pedc->desc_list_len, + pedc->lnk_srv_req_word2, + pedc->lnk_srv_req_word3, + pedc->lnk_srv_req_word4); + + /* Move to the Descriptors payload and start processing. */ + payload = (u8 *)(pedc) + sizeof(*pedc); + bytes = 0; + + /* Detect EDC response with no descriptors */ + if (pedc->desc_list_len <= 12) { + /* If there are no descriptors use FPIN only */ + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = RCV_SIG_FREQ_CYC_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + goto rsp_err; + } + /* Payload length in bytes is the response descriptor list + * length minus the 12 bytes of Link Service Request + * Information descriptor in the reply. + */ + desc_total_bytes = pedc->desc_list_len - 12; + + lpfc_sli_bemem_bcopy(payload, payload, desc_total_bytes); + while (bytes < desc_total_bytes) { + desctag = *((u32 *)payload); + if (desctag == CGN_DET_CAP_DESC_TAG) { + pcgndet = (struct cgn_det_desc *)payload; + lpfc_printf_log(phba, KERN_INFO, + LOG_ELS | LOG_CGN_MGMT, + "4616 CGN Desc Data: 0x%08x 0x%08x " + "0x%08x 0x%08x 0x%08x 0x%08x\n", + pcgndet->cgn_det_tag, + pcgndet->cgn_desc_len, + pcgndet->word2, + pcgndet->word3, + pcgndet->word4, + pcgndet->word5); + + /* Descriptor length does not account for 8 bytes of + * tag and length words. + */ + bytes += pcgndet->cgn_desc_len + 8; + payload += bytes; + + /* Compare driver and Fport capabilities and choose + * least common. + */ + lpfc_least_capable_settings(phba, pcgndet); + rcv_cap_desc = true; + } else if (desctag == LINK_FLT_CAP_DESC_TAG) { + plnkflt = (struct link_flt_desc *)payload; + lpfc_printf_log(phba, KERN_INFO, + LOG_ELS | LOG_CGN_MGMT, + "4617 Link Fault Desc Data: " + "0x%08x 0x%08x 0x%08x 0x%08x " + "0x%08x\n", + plnkflt->link_flt_cap_tag, + plnkflt->desc_len, + plnkflt->degrade_act_thld, + plnkflt->degrade_deact_thld, + plnkflt->fec_degrade_intvl); + + /* Descriptor length does not account for 8 bytes of + * tag and length words. + */ + bytes += plnkflt->desc_len + 8; + payload += bytes; + } else { + punk = (struct unknown_desc *)payload; + lpfc_printf_log(phba, KERN_ERR, + LOG_ELS | LOG_CGN_MGMT, + "4919 Unknown Desc Tag x%08x\n", + desctag); + + /* Descriptor length does not account for 8 bytes of + * tag and length words. + */ + bytes += punk->desc_len + 8; + payload += bytes; + } + } + + if (!rcv_cap_desc) + goto out; + + /* The FW needs to be updated with the negotiated congestion signal + * values. + */ + rsp_err: + lpfc_config_cgn_signal(phba); + + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(phba->pport); + lpfc_els_free_iocb(phba, cmdiocb); + return; + + out: + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(phba->pport); + lpfc_els_free_iocb(phba, cmdiocb); + + /* If there is a EDC error, move on to RDF */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + lpfc_issue_els_rdf(phba->pport, 0); +} + + /** + * lpfc_issue_els_edc - Exchange Diagnostic Capabilities with the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command IOCB. + * + * This routine issues an ELS EDC to the F-Port Controller to communicate + * this N_Port's support of hardware signals in its Congestion + * Capabilities Descriptor. + * + * Note: This routine does not check if one or more signals are + * set in the cgn_reg_signal parameter. The caller makes the + * decision to enforce cgn_reg_signal as nonzero or zero depending + * on the conditions. During Fabric requests, the driver + * requires cgn_reg_signals to be nonzero. But a dynamic request + * to set the congestion mode to OFF from Monitor or Manage + * would correctly issue an EDC with no signals enabled to + * turn off switch functionality and then update the FW. + * + * Return code + * 0 - Successfully issued edc command + * 1 - Failed to issue edc command + **/ +int +lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_els_edc_req *edc_req; + struct cgn_det_desc *cgn_desc; + u16 cmdsize; + struct lpfc_nodelist *ndlp; + u8 *pcmd = NULL; + u32 edc_req_size, cgn_desc_size; + extern int lpfc_fabric_cgn_frequency; + int rc; + + if (vport->port_type == LPFC_NPIV_PORT) + return -EACCES; + + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return -ENODEV; + + /* If HBA doesn't support signals, drop into RDF */ + if (!phba->cgn_init_reg_signal) + goto try_rdf; + + edc_req_size = sizeof(struct lpfc_els_edc_req); + cgn_desc_size = sizeof(struct cgn_det_desc); + cmdsize = edc_req_size + cgn_desc_size; + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_EDC); + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + goto try_rdf; + } + + /* Configure the payload for the supported Diagnostics capabilities. */ + pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + memset(pcmd, 0, cmdsize); + edc_req = (struct lpfc_els_edc_req *)pcmd; + edc_req->word0 = ELS_CMD_EDC; + edc_req->desc_list_len = cpu_to_be32(cgn_desc_size); + + /* Configure the congestion detection capability */ + cgn_desc = ((struct cgn_det_desc *)(pcmd + edc_req_size)); + cgn_desc->cgn_det_tag = cpu_to_be32(CGN_DET_CAP_DESC_TAG); + + /* Descriptor len doesn't include the tag or len fields. */ + cgn_desc->cgn_desc_len = cpu_to_be32(cgn_desc_size - 8); + bf_set(xmt_sig_cap, cgn_desc, XMT_SIG_CAP_NO_SPT); + bf_set(xmt_sig_freq_cyc, cgn_desc, XMT_SIG_FREQ_CYC_NO_SPT); + bf_set(xmt_sig_freq_scale, cgn_desc, XMT_SIG_FREQ_SCALE_NO_SPT); + + if (phba->cmf_active_mode == LPFC_CFG_OFF) { + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_NO_SPT); + bf_set(rcv_sig_freq_cyc, cgn_desc, 0); + bf_set(rcv_sig_freq_scale, cgn_desc, 0); + phba->cgn_sig_freq = 0; + } else { + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN) + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_WARN_SPT); + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_BOTH_SPT); + bf_set(rcv_sig_freq_cyc, cgn_desc, lpfc_fabric_cgn_frequency); + + /* We start negotiation with lpfc_fabric_cgn_frequency, after + * the completion we settle on the higher frequency. + */ + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + bf_set(rcv_sig_freq_scale, cgn_desc, RCV_SIG_FREQ_SCALE_MSEC); + } + + cgn_desc->word2 = cpu_to_be32(cgn_desc->word2); + cgn_desc->word3 = cpu_to_be32(cgn_desc->word3); + cgn_desc->word4 = cpu_to_be32(cgn_desc->word4); + cgn_desc->word5 = cpu_to_be32(cgn_desc->word5); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_CGN_MGMT, + "4623 Xmit EDC to remote " + "NPORT x%x reg_sig x%x reg_fpin:x%x\n", + ndlp->nlp_DID, phba->cgn_reg_signal, + phba->cgn_reg_fpin); + + phba->fc_stat.elsXmitEDC++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + goto try_rdf; + } + return 0; +try_rdf: + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + rc = lpfc_issue_els_rdf(vport, 0); + return rc; +} + /** * lpfc_issue_els_farpr - Issue a farp to an node on a vport * @vport: pointer to a host virtual N_Port data structure. @@ -3413,9 +4059,17 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) * to the event associated with the ndlp. **/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_els_retry_delay(unsigned long ptr) +#else lpfc_els_retry_delay(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr; +#else struct lpfc_nodelist *ndlp = from_timer(ndlp, t, nlp_delayfunc); +#endif struct lpfc_vport *vport = ndlp->vport; struct lpfc_hba *phba = vport->phba; unsigned long flags; @@ -3537,7 +4191,7 @@ lpfc_link_reset(struct lpfc_vport *vport) "2851 Attempt link reset\n"); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2852 Failed to allocate mbox memory"); return 1; } @@ -3559,7 +4213,7 @@ lpfc_link_reset(struct lpfc_vport *vport) mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2853 Failed to issue INIT_LINK " "mbox command, rc:x%x\n", rc); mempool_free(mbox, phba->mbox_mem_pool); @@ -3663,7 +4317,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOERR_ILLEGAL_COMMAND: - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0124 Retry illegal cmd x%x " "retry:x%x delay:x%x\n", cmd, cmdiocb->retry, delay); @@ -3709,6 +4363,16 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; delay = 100; break; + + case IOERR_SLI_ABORTED: + /* Retry the ELS command if it's a PLOGI. Possibly the + * rport just wasn't ready. + */ + if (cmd == ELS_CMD_PLOGI) { + retry = 1; + maxretry = 2; + } + break; } break; @@ -3735,10 +4399,14 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, case LSRJT_UNABLE_TPC: /* The driver has a VALID PLOGI but the rport has * rejected the PRLI - can't do it now. Delay - * for 1 second and try again - don't care about - * the explanation. + * for 1 second and try again. + * + * However, if explanation is REQ_UNSUPPORTED there's + * no point to retry PRLI. */ - if (cmd == ELS_CMD_PRLI || cmd == ELS_CMD_NVMEPRLI) { + if ((cmd == ELS_CMD_PRLI || cmd == ELS_CMD_NVMEPRLI) && + stat.un.b.lsRjtRsnCodeExp != + LSEXP_REQ_UNSUPPORTED) { delay = 1000; maxretry = lpfc_max_els_tries + 1; retry = 1; @@ -3773,7 +4441,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && (cmd == ELS_CMD_FDISC) && (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0125 FDISC Failed (x%x). " "Fabric out of resources\n", stat.un.lsRjtError); @@ -3812,7 +4481,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, LSEXP_NOTHING_MORE) { vport->fc_sparam.cmn.bbRcvSizeMsb &= 0xf; retry = 1; - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0820 FLOGI Failed (x%x). " "BBCredit Not Supported\n", stat.un.lsRjtError); @@ -3825,7 +4495,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) || (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID)) ) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0122 FDISC Failed (x%x). " "Fabric Detected Bad WWN\n", stat.un.lsRjtError); @@ -3846,12 +4517,14 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * on this rport. */ if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_REQ_UNSUPPORTED && cmd == ELS_CMD_PRLI) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_FCP_PRLI_RJT; - spin_unlock_irq(shost->host_lock); - retry = 0; - goto out_retry; + LSEXP_REQ_UNSUPPORTED) { + if (cmd == ELS_CMD_PRLI) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_FCP_PRLI_RJT; + spin_unlock_irq(shost->host_lock); + retry = 0; + goto out_retry; + } } break; } @@ -4003,7 +4676,7 @@ out_retry: } /* No retry ELS command to remote NPORT */ if (logerr) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0137 No retry ELS command x%x to remote " "NPORT x%x: Out of Resources: Error:x%x/%x\n", cmd, did, irsp->ulpStatus, @@ -4153,14 +4826,12 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; lpfc_els_free_data(phba, buf_ptr1); - elsiocb->context2 = NULL; } } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; lpfc_els_free_bpl(phba, buf_ptr); - elsiocb->context3 = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -4301,6 +4972,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; + if (!vport) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3177 ELS response failed\n"); + goto out; + } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -4356,23 +5032,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && - (!(vport->fc_flag & FC_PT2PT)) && - (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || - ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0314 PLOGI recov DID x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_rpi, ndlp->nlp_flag); - mp = mbox->ctx_buf; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, - mp->phys); - kfree(mp); + (!(vport->fc_flag & FC_PT2PT))) { + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + ndlp->nlp_state == + NLP_STE_REG_LOGIN_ISSUE) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY, + "0314 PLOGI recov " + "DID x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_rpi, + ndlp->nlp_flag); + mp = (struct lpfc_dmabuf *) + mbox->ctx_buf; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, + mp->phys); + kfree(mp); + } + mempool_free(mbox, phba->mbox_mem_pool); + goto out; } - mempool_free(mbox, phba->mbox_mem_pool); - goto out; } /* Increment reference count to ndlp to hold the @@ -4403,7 +5085,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; /* ELS rsp: Cannot issue reg_login for */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0138 ELS rsp: Cannot issue reg_login for x%x " "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -4637,6 +5319,15 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, lpfc_els_free_iocb(phba, elsiocb); return 1; } + + /* Xmit ELS ACC response tag */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " + "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "RPI: x%x, fc_flag x%x\n", + rc, elsiocb->iotag, elsiocb->sli4_xritag, + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi, vport->fc_flag); return 0; } @@ -4717,6 +5408,104 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, return 0; } + /** + * lpfc_issue_els_edc_rsp - Exchange Diagnostic Capabilities with the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to the original lpfc command iocb data structure. + * @ndlp: NPort to where rsp is directed + * + * This routine issues an EDC ACC RSP to the F-Port Controller to communicate + * this N_Port's support of hardware signals in its Congestion + * Capabilities Descriptor. + * + * Return code + * 0 - Successfully issued edc rsp command + * 1 - Failed to issue edc rsp command + **/ +static int +lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_els_edc_rsp *pedc; + struct cgn_det_desc *cgn_desc; + struct lpfc_iocbq *elsiocb; + IOCB_t *icmd, *cmd; + uint8_t *pcmd; + int cmdsize, rc, cnt; + + cmdsize = sizeof(struct lpfc_els_edc_rsp) + sizeof(struct cgn_det_desc); + elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, cmdiocb->retry, + ndlp, ndlp->nlp_DID, ELS_CMD_ACC); + if (!elsiocb) + return 1; + + icmd = &elsiocb->iocb; + cmd = &cmdiocb->iocb; + icmd->ulpContext = cmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = cmd->unsli3.rcvsli3.ox_id; + pcmd = (((struct lpfc_dmabuf *)elsiocb->context2)->virt); + memset(pcmd, 0, cmdsize); + + *((uint32_t *)(pcmd)) = ELS_CMD_ACC; + + pedc = (struct lpfc_els_edc_rsp *)pcmd; + cnt = cmdsize - (2 * sizeof(u32)); + pedc->desc_list_len = cpu_to_be32(cnt); + pedc->lnk_srv_req_word2 = cpu_to_be32(1); + pedc->lnk_srv_req_word3 = cpu_to_be32(sizeof(u32)); + pedc->lnk_srv_req_word4 = ELS_CMD_EDC; + + cgn_desc = (struct cgn_det_desc *)(pcmd + + sizeof(struct lpfc_els_edc_rsp)); + cgn_desc->cgn_det_tag = cpu_to_be32(CGN_DET_CAP_DESC_TAG); + cnt = sizeof(struct cgn_det_desc) - (2 * sizeof(u32)); + cgn_desc->cgn_desc_len = cpu_to_be32(cnt); + bf_set(xmt_sig_cap, cgn_desc, XMT_SIG_CAP_NO_SPT); + bf_set(xmt_sig_freq_cyc, cgn_desc, XMT_SIG_FREQ_CYC_NO_SPT); + bf_set(xmt_sig_freq_scale, cgn_desc, XMT_SIG_FREQ_SCALE_NO_SPT); + + if (phba->cmf_active_mode == LPFC_CFG_OFF) { + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_NO_SPT); + bf_set(rcv_sig_freq_cyc, cgn_desc, 0); + bf_set(rcv_sig_freq_scale, cgn_desc, 0); + phba->cgn_sig_freq = 0; + } else { + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN) + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_WARN_SPT); + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + bf_set(rcv_sig_cap, cgn_desc, RCV_SIG_CAP_BOTH_SPT); + bf_set(rcv_sig_freq_scale, cgn_desc, RCV_SIG_FREQ_SCALE_MSEC); + bf_set(rcv_sig_freq_cyc, cgn_desc, lpfc_fabric_cgn_frequency); + } + + cgn_desc->word2 = cpu_to_be32(cgn_desc->word2); + cgn_desc->word3 = cpu_to_be32(cgn_desc->word3); + cgn_desc->word4 = cpu_to_be32(cgn_desc->word4); + cgn_desc->word5 = cpu_to_be32(cgn_desc->word5); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, + "Issue EDC ACC: did:x%x flg:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, 0); + elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + + phba->fc_stat.elsXmitACC++; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + + /* Xmit ELS ACC response tag */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0152 Xmit EDC ACC response Status: x%x, IoTag: x%x, " + "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "RPI: x%x, fc_flag x%x\n", + rc, elsiocb->iotag, elsiocb->sli4_xritag, + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi, vport->fc_flag); + + if (rc == IOCB_ERROR) + lpfc_els_free_iocb(phba, elsiocb); + return rc; +} + /** * lpfc_els_rsp_adisc_acc - Prepare and issue acc response to adisc iocb cmd * @vport: pointer to a virtual N_Port data structure. @@ -4788,15 +5577,6 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, lpfc_els_free_iocb(phba, elsiocb); return 1; } - - /* Xmit ELS ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " - "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " - "RPI: x%x, fc_flag x%x\n", - rc, elsiocb->iotag, elsiocb->sli4_xritag, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi, vport->fc_flag); return 0; } @@ -5272,6 +6052,11 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) } } } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6452 Discover PLOGI %d flag x%x\n", + sentplogi, vport->fc_flag); + if (sentplogi) { lpfc_set_disctmo(vport); } @@ -5283,7 +6068,7 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) return sentplogi; } -static uint32_t +uint32_t lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc, uint32_t word0) { @@ -5295,7 +6080,7 @@ lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc, return sizeof(struct fc_rdp_link_service_desc); } -static uint32_t +uint32_t lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc, uint8_t *page_a0, uint8_t *page_a2) { @@ -5360,7 +6145,7 @@ lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc, return sizeof(struct fc_rdp_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc, READ_LNK_VAR *stat) { @@ -5389,7 +6174,7 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc, return sizeof(struct fc_rdp_link_error_status_desc); } -static uint32_t +uint32_t lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, struct lpfc_vport *vport) { @@ -5414,7 +6199,7 @@ lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat, return sizeof(struct fc_rdp_bbc_desc); } -static uint32_t +uint32_t lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) { @@ -5442,7 +6227,7 @@ lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba, return sizeof(struct fc_rdp_oed_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -5471,7 +6256,7 @@ lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba, return sizeof(struct fc_rdp_oed_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -5500,7 +6285,7 @@ lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba, return sizeof(struct fc_rdp_oed_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -5530,7 +6315,7 @@ lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba, } -static uint32_t +uint32_t lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2) @@ -5559,7 +6344,7 @@ lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba, return sizeof(struct fc_rdp_oed_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc, uint8_t *page_a0, struct lpfc_vport *vport) { @@ -5573,7 +6358,7 @@ lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc, return sizeof(struct fc_rdp_opd_sfp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat) { if (bf_get(lpfc_read_link_stat_gec2, stat) == 0) @@ -5590,7 +6375,7 @@ lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat) return sizeof(struct fc_fec_rdp_desc); } -static uint32_t +uint32_t lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) { uint16_t rdp_cap = 0; @@ -5659,7 +6444,7 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) return sizeof(struct fc_rdp_port_speed_desc); } -static uint32_t +uint32_t lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc, struct lpfc_vport *vport) { @@ -5676,7 +6461,7 @@ lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc, return sizeof(struct fc_rdp_port_name_desc); } -static uint32_t +uint32_t lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -5700,7 +6485,7 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, return sizeof(struct fc_rdp_port_name_desc); } -static void +void lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, int status) { @@ -5800,7 +6585,7 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, phba->fc_stat.elsXmitACC++; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + if(rc == IOCB_ERROR) lpfc_els_free_iocb(phba, elsiocb); kfree(rdp_context); @@ -5831,9 +6616,10 @@ error: lpfc_els_free_iocb(phba, elsiocb); free_rdp_context: kfree(rdp_context); + return; } -static int +int lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) { LPFC_MBOXQ_t *mbox = NULL; @@ -5891,7 +6677,6 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_rdp_context *rdp_context; IOCB_t *cmd = NULL; struct ls_rjt stat; - if (phba->sli_rev < LPFC_SLI_REV4 || bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < LPFC_SLI_INTF_IF_TYPE_2) { @@ -5958,7 +6743,6 @@ error: return 1; } - static void lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { @@ -5970,7 +6754,7 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct ls_rjt *stat; union lpfc_sli4_cfg_shdr *shdr; struct lpfc_lcb_context *lcb_context; - struct fc_lcb_res_frame *lcb_res; + struct fc_lcb_res_frame *lcb_res; uint32_t cmdsize, shdr_status, shdr_add_status; int rc; @@ -5986,14 +6770,14 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX, - "0194 SET_BEACON_CONFIG mailbox " - "completed with status x%x add_status x%x," - " mbx status x%x\n", - shdr_status, shdr_add_status, mb->mbxStatus); + "0194 SET_BEACON_CONFIG mailbox " + "completed with status x%x add_status x%x," + " mbx status x%x\n", + shdr_status, shdr_add_status, mb->mbxStatus); - if ((mb->mbxStatus != MBX_SUCCESS) || shdr_status || - (shdr_add_status == ADD_STATUS_OPERATION_ALREADY_ACTIVE) || - (shdr_add_status == ADD_STATUS_INVALID_REQUEST)) { + if (mb->mbxStatus != MBX_SUCCESS || shdr_status || + shdr_add_status == ADD_STATUS_OPERATION_ALREADY_ACTIVE || + shdr_add_status == ADD_STATUS_INVALID_REQUEST) { mempool_free(pmb, phba->mbox_mem_pool); goto error; } @@ -6001,8 +6785,8 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); cmdsize = sizeof(struct fc_lcb_res_frame); elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); + lpfc_max_els_tries, ndlp, + ndlp->nlp_DID, ELS_CMD_ACC); /* Decrement the ndlp reference count from previous mbox command */ lpfc_nlp_put(ndlp); @@ -6062,6 +6846,7 @@ error: lpfc_els_free_iocb(phba, elsiocb); free_lcb_context: kfree(lcb_context); + return; } static int @@ -6069,7 +6854,7 @@ lpfc_sli4_set_beacon(struct lpfc_vport *vport, struct lpfc_lcb_context *lcb_context, uint32_t beacon_state) { - struct lpfc_hba *phba = vport->phba; + struct lpfc_hba *phba = vport->phba; union lpfc_sli4_cfg_shdr *cfg_shdr; LPFC_MBOXQ_t *mbox = NULL; uint32_t len; @@ -6144,7 +6929,7 @@ lpfc_sli4_set_beacon(struct lpfc_vport *vport, * * This routine processes an unsolicited LCB(LINK CABLE BEACON) IOCB. * First, the payload of the unsolicited LCB is checked. - * Then based on Subcommand beacon will either turn on or off. + * Then based on Subcommand either Becon will turn on or off. * * Return code * 0 - Sent the acc response @@ -6154,10 +6939,10 @@ static int lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { - struct lpfc_hba *phba = vport->phba; + struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; uint8_t *lp; - struct fc_lcb_request_frame *beacon; + struct fc_lcb_request_frame *beacon; struct lpfc_lcb_context *lcb_context; uint8_t state, rjt_err; struct ls_rjt stat; @@ -6206,8 +6991,8 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lcb_context->rx_id = cmdiocb->iocb.ulpContext; lcb_context->ndlp = lpfc_nlp_get(ndlp); if (lpfc_sli4_set_beacon(vport, lcb_context, state)) { - lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_ELS, "0193 failed to send mail box"); + lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_TRACE_EVENT, + "0193 failed to send mail box"); kfree(lcb_context); lpfc_nlp_put(ndlp); rjt_err = LSRJT_UNABLE_TPC; @@ -6416,7 +7201,7 @@ lpfc_send_rscn_event(struct lpfc_vport *vport, rscn_event_data = kmalloc(sizeof(struct lpfc_rscn_event_header) + payload_len, GFP_KERNEL); if (!rscn_event_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0147 Failed to allocate memory for RSCN event\n"); return; } @@ -6501,6 +7286,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (ndlp->nlp_fc4_type & NLP_FC4_NVME && ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) lpfc_nvme_rescan_port(vport, ndlp); + return 0; } @@ -6682,9 +7468,10 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* RSCN processed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0215 RSCN processed Data: x%x x%x x%x x%x\n", + "0215 RSCN processed Data: x%x x%x x%x x%x x%x x%x\n", vport->fc_flag, 0, vport->fc_rscn_id_cnt, - vport->port_state); + vport->port_state, vport->num_disc_nodes, + vport->gidft_inp); /* To process RSCN, first compare RSCN data with NameServer */ vport->fc_ns_retry = 0; @@ -6792,7 +7579,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* An FLOGI ELS command was received from DID in Loop Mode */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0113 An FLOGI ELS command x%x was " "received from DID x%x in Loop Mode\n", cmd, did); @@ -7045,16 +7832,16 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * * This routine is the completion callback function for the MBX_READ_LNK_STAT * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It + * (ACC) response to a Read Link Status (RLS) unsolicited IOCB event. It * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics + * mailbox command, constructs the RLS response with the link statistics * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. + * response to the RLS. * * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp * will be incremented by 1 for holding the ndlp and the reference to ndlp * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. + * callback function to the RLS Accept Response ELS IOCB command. * **/ static void @@ -7075,8 +7862,8 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff); oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff); - pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; + pmb->ctx_buf = NULL; if (mb->mbxStatus) { mempool_free(pmb, phba->mbox_mem_pool); @@ -7125,109 +7912,13 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_els_free_iocb(phba, elsiocb); } -/** - * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for the MBX_READ_LNK_STAT - * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It - * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics - * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - **/ -static void -lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - IOCB_t *icmd; - RPS_RSP *rps_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint16_t status; - uint16_t oxid; - uint16_t rxid; - uint32_t cmdsize; - - mb = &pmb->u.mb; - - ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff); - oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff); - pmb->ctx_ndlp = NULL; - pmb->ctx_buf = NULL; - - if (mb->mbxStatus) { - mempool_free(pmb, phba->mbox_mem_pool); - return; - } - - cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - /* Decrement the ndlp reference count from previous mbox command */ - lpfc_nlp_put(ndlp); - - if (!elsiocb) - return; - - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - rps_rsp = (RPS_RSP *)pcmd; - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) - status = 0x10; - else - status = 0x8; - if (phba->pport->fc_flag & FC_FABRIC) - status |= 0x4; - - rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = cpu_to_be16(status); - rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - /* Xmit ELS RPS ACC response tag */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); - return; -} - /** * lpfc_els_rcv_rls - Process an unsolicited rls iocb * @vport: pointer to a host virtual N_Port data structure. * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Port Status (RPL) IOCB received as an + * This routine processes Read Link Status (RLS) IOCB received as an * ELS unsolicited event. It first checks the remote port state. If the * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE * state, it invokes the lpfc_els_rsl_reject() routine to send the reject @@ -7249,7 +7940,7 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RLS request and done with it */ goto reject_out; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); @@ -7297,7 +7988,7 @@ reject_out: * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp * will be incremented by 1 for holding the ndlp and the reference to ndlp * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. + * callback function to the RTV Accept Response ELS IOCB command. * * Return codes * 0 - Successfully processed rtv iocb (currently always return 0) @@ -7316,7 +8007,7 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RTV request and done with it */ goto reject_out; cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); @@ -7369,84 +8060,7 @@ reject_out: return 0; } -/* lpfc_els_rcv_rps - Process an unsolicited rps iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port Status (RPS) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsp_reject() routine to send the reject - * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command - * for reading the HBA link statistics. It is for the callback function, - * lpfc_els_rsp_rps_acc(), set to the MBX_READ_LNK_STAT mailbox command - * to actually sending out RPS Accept (ACC) response. - * - * Return codes - * 0 - Successfully processed rps iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t *lp; - uint8_t flag; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; - RPS *rps; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - flag = (be32_to_cpu(*lp++) & 0xf); - rps = (RPS *) lp; - - if ((flag == 0) || - ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) || - ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname, - sizeof(struct lpfc_name)) == 0))) { - - printk("Fix me....\n"); - dump_stack(); - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); - if (mbox) { - lpfc_read_lnk_stat(phba, mbox); - mbox->ctx_buf = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - /* Mbox completion will send ELS Response */ - return 0; - /* Decrement reference count used for the failed mbox - * command. - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - } - } - -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/* lpfc_issue_els_rrq - Process an unsolicited rps iocb +/* lpfc_issue_els_rrq - Process an unsolicited rrq iocb * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. * @did: DID of the target. @@ -7527,10 +8141,7 @@ int lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq) { struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport, - rrq->nlp_DID); - if (!ndlp) - return 1; - + rrq->nlp_DID); if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag)) return lpfc_issue_els_rrq(rrq->vport, ndlp, rrq->nlp_DID, rrq); @@ -7844,6 +8455,137 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 0; } +#ifndef BUILD_BRCMFCOE +/** + * lpfc_els_rcv_auth - Process an unsolicited auth iocb + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - Successfully processed echo iocb (currently always return 0) + **/ +static int +lpfc_els_rcv_auth(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct ls_rjt stat; + + if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && + (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) + /* reject the unsolicited auth request and be done with it */ + goto reject_out; + + /* Send back ACC */ + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + + return lpfc_auth_handle_cmd(vport, cmdiocb, ndlp); + +reject_out: + /* issue rejection response */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_PORT_LOGIN_REQ; + stat.un.b.vendorUnique = 0; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return 0; +} +#endif + +/** + * lpfc_els_rcv_edc - Process an unsolicited EDC iocb + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - Successfully processed echo iocb (currently always return 0) + **/ +static int +lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_els_edc_req *edc_req; + struct cgn_det_desc *pcgndet; + struct link_flt_desc *plnkflt; + struct unknown_desc *punk; + uint8_t *payload; + uint32_t *ptr; + int sz, cnt; + + payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt; + /* Swap payload bytes back to cpu mode.*/ + lpfc_sli_bemem_bcopy(payload, payload, LPFC_BPL_SIZE); + + edc_req = (struct lpfc_els_edc_req *)payload; + sz = edc_req->desc_list_len; + + ptr = (uint32_t *)payload; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "3319 Rcv EDC payload len %d: x%x x%x x%x\n", sz, + *ptr, *(ptr + 1), *(ptr + 2)); + + /* No signal support unless there is a congestion descriptor */ + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = RCV_SIG_FREQ_CYC_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + + if (sz <= sizeof(struct lpfc_els_edc_req)) + goto out; + + /* now point to the first descriptor */ + sz -= sizeof(struct lpfc_els_edc_req); + payload += sizeof(struct lpfc_els_edc_req); + punk = (struct unknown_desc *)payload; + + while (sz > 0) { + switch (punk->unk_tag) { + case CGN_DET_CAP_DESC_TAG: + pcgndet = (struct cgn_det_desc *)payload; + phba->cgn_reg_fpin = phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = phba->cgn_init_reg_signal; + + /* We start negotiation with lpfc_fabric_cgn_frequency. + * When we process the EDC, we will settle on the + * higher frequency. + */ + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + + /* process congestion descriptor */ + lpfc_least_capable_settings(phba, pcgndet); + + sz = 0; /* break from while loop */ + break; + case LINK_FLT_CAP_DESC_TAG: + plnkflt = (struct link_flt_desc *)payload; + /* No action for Link Fault descriptor for now */ + cnt = (2 * sizeof(u32) + plnkflt->desc_len); + sz -= cnt; + + /* goto the next descriptor, if any */ + payload += cnt; + punk = (struct unknown_desc *)payload; + break; + default: + /* A descriptor we are not interested in */ + cnt = (2 * sizeof(u32) + punk->desc_len); + sz -= cnt; + + /* goto the next descriptor, if any */ + payload += cnt; + punk = (struct unknown_desc *)payload; + break; + } + } +out: + /* Need to send back an ACC */ + lpfc_issue_els_edc_rsp(vport, cmdiocb, ndlp); + + lpfc_config_cgn_signal(phba); + return 0; +} + /** * lpfc_els_timeout - Handler funciton to the els timer * @ptr: holder for the timer function associated data. @@ -7855,9 +8597,17 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * lpfc_els_timeout_handler() to work on the posted event WORKER_ELS_TMO. **/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_els_timeout(unsigned long ptr) +#else lpfc_els_timeout(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_vport *vport = (struct lpfc_vport *) ptr; +#else struct lpfc_vport *vport = from_timer(vport, t, els_tmofunc); +#endif struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; @@ -7903,19 +8653,13 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) if (unlikely(!pring)) return; - if ((phba->pport->load_flag & FC_UNLOADING)) + if (phba->pport->load_flag & FC_UNLOADING) return; + spin_lock_irq(&phba->hbalock); if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); - if ((phba->pport->load_flag & FC_UNLOADING)) { - if (phba->sli_rev == LPFC_SLI_REV4) - spin_unlock(&pring->ring_lock); - spin_unlock_irq(&phba->hbalock); - return; - } - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { cmd = &piocb->iocb; @@ -7961,7 +8705,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { cmd = &piocb->iocb; - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0127 ELS timeout Data: x%x x%x x%x " "x%x\n", els_command, remote_ID, cmd->ulpCommand, cmd->ulpIoTag); @@ -7971,6 +8715,9 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) spin_unlock_irq(&phba->hbalock); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (!list_empty(&pring->txcmplq)) if (!(phba->pport->load_flag & FC_UNLOADING)) mod_timer(&vport->els_tmofunc, @@ -8070,8 +8817,11 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) lpfc_sli_issue_abort_iotag(phba, pring, piocb); spin_unlock_irqrestore(&phba->hbalock, iflags); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (!list_empty(&abort_list)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3387 abort list for txq not empty\n"); INIT_LIST_HEAD(&abort_list); @@ -8242,7 +8992,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, if (*payload == ELS_CMD_LOGO) { logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); if (!logo_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0148 Failed to allocate memory " "for LOGO event\n"); return; @@ -8252,7 +9002,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, els_data = kmalloc(sizeof(struct lpfc_els_event_header), GFP_KERNEL); if (!els_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0149 Failed to allocate memory " "for ELS event\n"); return; @@ -8300,6 +9050,407 @@ lpfc_send_els_event(struct lpfc_vport *vport, return; } +DECLARE_ENUM2STR_LOOKUP(lpfc_get_tlv_dtag_nm, fc_ls_tlv_dtag, + FC_LS_TLV_DTAG_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_li_event_nm, fc_fpin_li_event_types, + FC_FPIN_LI_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_deli_event_nm, fc_fpin_deli_event_types, + FC_FPIN_DELI_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_event_nm, fc_fpin_congn_event_types, + FC_FPIN_CONGN_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_sev_nm, + fc_fpin_congn_sev_types, + FC_FPIN_CONGN_SEV_INIT); + +/** + * lpfc_display_fpin_wwpn - Display WWPNs accessible by the attached port + * @phba: Pointer to phba object. + * @cnt: count of WWPNs in FPIN payload + * + * This routine is called by LI and PC descriptors. + * Limit the number of WWPNs displayed to 6 log messages, 6 per log message + */ +void +lpfc_display_fpin_wwpn(struct lpfc_hba *phba, __be64 *wwnlist, u32 cnt) +{ + char buf[LPFC_FPIN_WWPN_LINE_SZ]; + __be64 wwn; + u64 wwpn; + int i, len; + int line = 0; + int wcnt = 0; + bool endit = false; + + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, "Accessible WWPNs:"); + for (i = 0; i < cnt; i++) { + /* Are we on the last WWPN */ + if (i == (cnt - 1)) + endit = true; + + /* Extract the next WWPN from the payload */ + wwn = *wwnlist++; + wwpn = be64_to_cpu(wwn); + len += scnprintf(buf + len, LPFC_FPIN_WWPN_LINE_SZ, + " %016llx", wwpn); + + /* Log a message if we are on the last WWPN + * or if we hit the max allowed per message. + */ + wcnt++; + if (wcnt == LPFC_FPIN_WWPN_LINE_CNT || endit) { + buf[len] = 0; + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4686 %s\n", buf); + + /* Check if we reached the last WWPN */ + if (endit) + return; + + /* Limit the number of log message displayed per FPIN */ + line++; + if (line == LPFC_FPIN_WWPN_NUM_LINE) { + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4687 %d WWPNs Truncated\n", + cnt - i - 1); + return; + } + + /* Start over with next log message */ + wcnt = 0; + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, + "Additional WWPNs:"); + } + } +} + +/** + * lpfc_els_rcv_fpin_li - Process an FPIN Link Integrity Event. + * @phba: Pointer to hba object. + * @tlv: Pointer to the Link Integrity Notification Descriptor. + * + * This function processes a Delivery FPIN event by + * logging a message. It retuns 1 to indicate deliver this message + * to the upper layer. + **/ +static void +lpfc_els_rcv_fpin_li(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_li_desc *li = (struct fc_fn_li_desc *)tlv; + const char *li_evt_str; + u32 li_evt, cnt; + + li_evt = be16_to_cpu(li->event_type); + li_evt_str = lpfc_get_fpin_li_event_nm(li_evt); + cnt = be32_to_cpu(li->pname_count); + + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4680 FPIN Link Integrity %s (x%x) " + "Detecting PN x%016llx Attached PN x%016llx " + "Duration %d mSecs Count %d Port Cnt %d\n", + li_evt_str, li_evt, + be64_to_cpu(li->detecting_wwpn), + be64_to_cpu(li->attached_wwpn), + be32_to_cpu(li->event_threshold), + be32_to_cpu(li->event_count), cnt); + + lpfc_display_fpin_wwpn(phba, (__be64 *)&li->pname_list, cnt); +} + +/** + * lpfc_els_rcv_fpin_del - Process an FPIN Delivery Event. + * @phba: Pointer to hba object. + * @tlv: Pointer to the Delivery Notification Descriptor TLV + * + * This function processes a link integrity FPIN event by + * logging a message. It retuns 1 to indicate deliver this message + * to the upper layer. + **/ +static void +lpfc_els_rcv_fpin_del(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_deli_desc *del = (struct fc_fn_deli_desc *)tlv; + const char *del_rsn_str; + u32 del_rsn; + __be32 *frame; + + del_rsn = be16_to_cpu(del->deli_reason_code); + del_rsn_str = lpfc_get_fpin_deli_event_nm(del_rsn); + + /* Skip over desc_tag/desc_len header to payload */ + frame = (__be32 *)(del + 1); + + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4681 FPIN Delivery %s (x%x) " + "Detecting PN x%016llx Attached PN x%016llx " + "DiscHdr0 x%08x " + "DiscHdr1 x%08x DiscHdr2 x%08x DiscHdr3 x%08x " + "DiscHdr4 x%08x DiscHdr5 x%08x\n", + del_rsn_str, del_rsn, + be64_to_cpu(del->detecting_wwpn), + be64_to_cpu(del->attached_wwpn), + be32_to_cpu(frame[0]), + be32_to_cpu(frame[1]), + be32_to_cpu(frame[2]), + be32_to_cpu(frame[3]), + be32_to_cpu(frame[4]), + be32_to_cpu(frame[5])); +} + +/** + * lpfc_els_rcv_fpin_peer_cgn - Process a FPIN Peer Congestion Event. + * @phba: Pointer to hba object. + * @tlv: Pointer to the Peer Congestion Notification Descriptor TLV + * + * This function processes a Peer Congestion FPIN event by + * logging a message. It retuns 1 to indicate deliver this message + * to the upper layer. + **/ +static void +lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_peer_congn_desc *pc = (struct fc_fn_peer_congn_desc *)tlv; + const char *pc_evt_str; + u32 pc_evt, cnt; + + pc_evt = be16_to_cpu(pc->event_type); + pc_evt_str = lpfc_get_fpin_congn_event_nm(pc_evt); + cnt = be32_to_cpu(pc->pname_count); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_ELS, + "4684 FPIN Peer Congestion %s (x%x) " + "Duration %d mSecs " + "Detecting PN x%016llx Attached PN x%016llx " + "Impacted Port Cnt %d\n", + pc_evt_str, pc_evt, + be32_to_cpu(pc->event_period), + be64_to_cpu(pc->detecting_wwpn), + be64_to_cpu(pc->attached_wwpn), + cnt); + + lpfc_display_fpin_wwpn(phba, (__be64 *)&pc->pname_list, cnt); +} + +/** + * lpfc_els_rcv_fpin_cgn - Process an FPIN Congestion notification + * @phba: Pointer to hba object. + * @tlv: Pointer to the Congestion Notification Descriptor TLV + * + * This function processes an FPIN Congestion Notifiction. The notification + * could be an Alarm or Warning. This routine feeds that data into driver's + * running congestion algorithm. It also processes the FPIN by + * logging a message. It retuns 1 to indicate deliver this message + * to the upper layer or 0 to indicate don't deliver it. + **/ +static int +lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct lpfc_cgn_info *cp; + struct fc_fn_congn_desc *cgn = (struct fc_fn_congn_desc *)tlv; + const char *cgn_evt_str; + u32 cgn_evt; + const char *cgn_sev_str; + u32 cgn_sev; + uint16_t value; + u32 crc; + bool nm_log = false; + int rc = 1; + + cgn_evt = be16_to_cpu(cgn->event_type); + cgn_evt_str = lpfc_get_fpin_congn_event_nm(cgn_evt); + cgn_sev = cgn->severity; + cgn_sev_str = lpfc_get_fpin_congn_sev_nm(cgn_sev); + + /* The driver only takes action on a Credit Stall or Oversubscription + * event type to engage the IO algorithm. The driver prints an + * unmaskable message only for Lost Credit and Credit Stall. + * TODO: Still need to have definition of host action on clear, + * lost credit and device specific event types. + */ + switch (cgn_evt) { + case FPIN_CONGN_LOST_CREDIT: + nm_log = true; + break; + case FPIN_CONGN_CREDIT_STALL: + nm_log = true; + /* fall through */ + case FPIN_CONGN_OVERSUBSCRIPTION: + if (cgn_evt == FPIN_CGN_EVT_OVERSUB) + nm_log = false; + switch (cgn_sev) { + case FPIN_CONGN_SEV_ERROR: + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) { + /* Track of alarm cnt for cgn_info */ + atomic_inc(&phba->cgn_fabric_alarm_cnt); + /* Track of alarm cnt for SYNC_WQE */ + atomic_inc(&phba->cgn_sync_alarm_cnt); + } + goto cleanup; + } + break; + case FPIN_CONGN_SEV_WARNING: + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) { + /* Track of warning cnt for cgn_info */ + atomic_inc(&phba->cgn_fabric_warn_cnt); + /* Track of warning cnt for SYNC_WQE */ + atomic_inc(&phba->cgn_sync_warn_cnt); + } +cleanup: + /* Save frequency in ms */ + phba->cgn_fpin_frequency = + be32_to_cpu(cgn->event_period); + value = phba->cgn_fpin_frequency; + if (phba->cgn_i) { + cp = (struct lpfc_cgn_info *) + phba->cgn_i->virt; + if (phba->cgn_reg_fpin & + LPFC_CGN_FPIN_ALARM) + cp->cgn_alarm_freq = + cpu_to_le16(value); + if (phba->cgn_reg_fpin & + LPFC_CGN_FPIN_WARN) + cp->cgn_warn_freq = + cpu_to_le16(value); + crc = lpfc_cgn_calc_crc32 + (cp, + LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + } + + /* Don't deliver to upper layer since + * driver took action on this tlv. + */ + rc = 0; + } + break; + } + break; + } + + /* Change the log level to unmaskable for the following event types. */ + lpfc_printf_log(phba, (nm_log ? KERN_ERR : KERN_INFO), + LOG_CGN_MGMT | LOG_ELS, + "4683 FPIN CONGESTION %s type %s (x%x) Event " + "Duration %d mSecs\n", + cgn_sev_str, cgn_evt_str, cgn_evt, + be32_to_cpu(cgn->event_period)); + return rc; +} + +void +lpfc_els_rcv_fpin(struct lpfc_vport *vport, void *p, u32 fpin_length) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_els_fpin *fpin = (struct lpfc_els_fpin *)p; + struct fc_tlv_desc *tlv, *first_tlv, *current_tlv; + const char *dtag_nm; + int desc_cnt = 0, bytes_remain, cnt; + u32 dtag, deliver = 0; + int len; + + /* FPINs handled only if we are in the right discovery state */ + if (vport->port_state < LPFC_DISC_AUTH) + return; + + /* make sure there is the full fpin header */ + if (fpin_length < sizeof(struct lpfc_els_fpin)) + return; + + /* Sanity check descriptor length. The desc_len does not include + * 1 word for the ELS command and 1 word for the desc_len itself. + */ + len = be32_to_cpu(fpin->desc_len); + if (fpin_length < len + (2 * sizeof(uint32_t))) { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4671 Bad FPIN list length %d: %d\n", + len, fpin_length); + return; + } + + tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0]; + first_tlv = tlv; + bytes_remain = fpin_length - offsetof(struct lpfc_els_fpin, fpin_desc); + bytes_remain = min_t(u32, bytes_remain, be32_to_cpu(fpin->desc_len)); + + /* process each descriptor seperately */ + while (bytes_remain >= FC_TLV_DESC_HDR_SZ && + bytes_remain >= FC_TLV_DESC_SZ_FROM_LENGTH(tlv)) { + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + lpfc_els_rcv_fpin_li(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_DELIVERY: + lpfc_els_rcv_fpin_del(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_PEER_CONGEST: + lpfc_els_rcv_fpin_peer_cgn(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_CONGESTION: + deliver = lpfc_els_rcv_fpin_cgn(phba, tlv); + break; + default: + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4678 unknown FPIN descriptor[%d]: " + "tag x%x (%s)\n", + desc_cnt, dtag, dtag_nm); + + /* If descriptor is bad, drop the rest of the data */ + return; + } + lpfc_cgn_update_stat(phba, dtag); + cnt = be32_to_cpu(tlv->desc_len); + + /* Sanity check descriptor length. The desc_len does not include + * 1 word for the desc_tag and 1 word for the desc_len itself. + */ + len -= (cnt + (2 * sizeof(uint32_t))); + if (len < 0) { + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4672 Bad FPIN descriptor length " + "%d: %d %d %s\n", + cnt, len, fpin_length, dtag_nm); + return; + } + + current_tlv = tlv; + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0) || defined(BUILD_RHEL83) + /* Format payload such that the FPIN delivered to the + * upper layer is a single descriptor FPIN. + */ + if (desc_cnt) + memcpy(first_tlv, current_tlv, + (cnt + sizeof(struct lpfc_els_fpin))); + + /* Adjust the length so that it only reflects a + * single descriptor FPIN. + */ + fpin_length = cnt + sizeof(struct lpfc_els_fpin); + fpin->desc_len = cpu_to_be32(fpin_length); + fpin_length += sizeof(struct lpfc_els_fpin); /* entire FPIN */ + + /* Send every descriptor individually to the upper layer */ + if (deliver) + fc_host_fpin_rcv(lpfc_shost_from_vport(vport), + fpin_length, (char *)fpin); +#endif + desc_cnt++; + } +} /** * lpfc_els_unsol_buffer - Process an unsolicited event data buffer @@ -8322,7 +9473,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; - uint32_t *payload; + uint32_t *payload, payload_len; uint32_t cmd, did, newnode; uint8_t rjt_exp, rjt_err = 0, init_link = 0; IOCB_t *icmd = &elsiocb->iocb; @@ -8333,9 +9484,13 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, newnode = 0; payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + payload_len = elsiocb->iocb.unsli3.rcvsli3.acc_len; cmd = *payload; - if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) + if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) { lpfc_post_buffer(phba, pring, 1); + if (icmd->ulpBdeCount == 2) + lpfc_post_buffer(phba, pring, 1); + } did = icmd->un.rcvels.remoteID; if (icmd->ulpStatus) { @@ -8396,8 +9551,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, spin_lock_irq(shost->host_lock); if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) { spin_unlock_irq(shost->host_lock); - if (newnode) - lpfc_nlp_put(ndlp); goto dropit; } spin_unlock_irq(shost->host_lock); @@ -8405,7 +9558,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, elsiocb->context1 = lpfc_nlp_get(ndlp); elsiocb->vport = vport; - if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { + /* + * Since RSCN and AUTH commands define + * other bytes in 4-byte payload, lets mask those off + */ + if (((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) || + ((cmd & ELS_CMD_MASK) == ELS_CMD_AUTH)) { cmd &= ELS_CMD_MASK; } /* ELS command received from NPORT */ @@ -8625,16 +9783,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (newnode) lpfc_nlp_put(ndlp); break; - case ELS_CMD_RPS: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPS: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRPS++; - lpfc_els_rcv_rps(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV RPL: did:x%x/ste:x%x flg:x%x", @@ -8689,13 +9837,33 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_INVALID_OX_RX; break; +#ifndef BUILD_BRCMFCOE + case ELS_CMD_AUTH: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV AUTH: did:x%x/ste:x%x " + "flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvAUTH++; + lpfc_els_rcv_auth(vport, elsiocb, ndlp); + if (newnode) + lpfc_nlp_put(ndlp); + break; +#endif case ELS_CMD_FPIN: - /* - * Received FPIN from fabric - pass it to the - * transport FPIN handler. - */ - fc_host_fpin_rcv(shost, elsiocb->iocb.unsli3.rcvsli3.acc_len, - (char *)payload); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV FPIN: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvFPIN++; + + lpfc_els_rcv_fpin(vport, payload, payload_len); + + /* There are no replies, so no rjt codes */ + break; + case ELS_CMD_EDC: + phba->fc_stat.elsRcvEDC++; + lpfc_els_rcv_edc(vport, elsiocb, ndlp); break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8707,7 +9875,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; /* Unknown ELS command received from NPORT */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) @@ -8752,7 +9920,7 @@ lsrjt: dropit: if (vport && !(vport->load_flag & FC_UNLOADING)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); @@ -8818,37 +9986,39 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { elsiocb->context2 = bdeBuf1; + if (icmd->ulpBdeCount == 2) + elsiocb->context3 = bdeBuf2; } else { paddr = getPaddr(icmd->un.cont64[0].addrHigh, icmd->un.cont64[0].addrLow); elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring, paddr); + if (icmd->ulpBdeCount == 2) { + paddr = getPaddr(icmd->un.cont64[1].addrHigh, + icmd->un.cont64[1].addrLow); + elsiocb->context3 = lpfc_sli_ringpostbuf_get(phba, + pring, + paddr); + } } lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); /* * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting context2 to NULL. + * if they are done with "mp" by setting context2/context3 to NULL. */ if (elsiocb->context2) { lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2); elsiocb->context2 = NULL; } - /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */ - if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) && - icmd->ulpBdeCount == 2) { - elsiocb->context2 = bdeBuf2; - lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); - /* free mp if we are done with it */ - if (elsiocb->context2) { - lpfc_in_buf_free(phba, elsiocb->context2); - elsiocb->context2 = NULL; - } + if (elsiocb->context3) { + lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context3); + elsiocb->context3 = NULL; } } -static void +void lpfc_start_fdmi(struct lpfc_vport *vport) { struct lpfc_nodelist *ndlp; @@ -8902,7 +10072,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); if (vport->fc_flag & FC_DISC_DELAYED) { spin_unlock_irq(shost->host_lock); - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3334 Delay fc port discovery for %d seconds\n", phba->fc_ratov); mod_timer(&vport->delayed_disc_tmo, @@ -8920,7 +10090,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0251 NameServer login: no memory\n"); return; } @@ -8932,7 +10102,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0348 NameServer login: node freed\n"); return; } @@ -8943,7 +10113,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0252 Cannot issue NameServer login\n"); return; } @@ -8980,7 +10150,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0915 Register VPI failed : Status: x%x" " upd bit: x%x \n", mb->mbxStatus, mb->un.varRegVpi.upd); @@ -9010,8 +10180,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, - KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "2732 Failed to issue INIT_VPI" " mailbox command\n"); } else { @@ -9048,6 +10218,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); else { +#ifndef BUILD_BRCMFCOE + ndlp = lpfc_findnode_did(vport, Fabric_DID); + /* check for authentication requirement */ + rc = lpfc_auth_start(vport, ndlp); + if (rc) { + /* + * If the physical port is + * instantiated using FDISC, + * do not start vport discovery. + */ + if (vport->port_state != LPFC_FDISC) + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } +#else /* * If the physical port is instantiated using * FDISC, do not start vport discovery. @@ -9055,6 +10240,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (vport->port_state != LPFC_FDISC) lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); +#endif } } else lpfc_do_scr_ns_plogi(phba, vport); @@ -9099,12 +10285,12 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_nlp_put(ndlp); mempool_free(mbox, phba->mbox_mem_pool); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0253 Register VPI: Can't send mbox\n"); goto mbox_err_exit; } } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0254 Register VPI: no memory\n"); goto mbox_err_exit; } @@ -9266,7 +10452,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; /* FDISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0126 FDISC failed. (x%x/x%x)\n", irsp->ulpStatus, irsp->un.ulpWord[4]); goto fdisc_failed; @@ -9388,7 +10574,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ELS_CMD_FDISC); if (!elsiocb) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0255 Issue FDISC: no IOCB\n"); return 1; } @@ -9442,7 +10628,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0256 Issue FDISC: Cannot send IOCB\n"); return 1; } @@ -9572,9 +10758,17 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * posted event WORKER_FABRIC_BLOCK_TMO. **/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_fabric_block_timeout(unsigned long ptr) +#else lpfc_fabric_block_timeout(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_hba *phba = (struct lpfc_hba *) ptr; +#else struct lpfc_hba *phba = from_timer(phba, t, fabric_block_timer); +#endif unsigned long iflags; uint32_t tmo_posted; @@ -9707,7 +10901,8 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct ls_rjt stat; - BUG_ON((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC); + if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC) + BUG(); switch (rspiocb->iocb.ulpStatus) { case IOSTAT_NPORT_RJT: @@ -9974,7 +11169,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, rxid, 1); /* Check if TXQ queue needs to be serviced */ - if (pring && !list_empty(&pring->txq)) + if (pring && (!(list_empty(&pring->txq)))) lpfc_worker_wake_up(phba); return; } @@ -10023,8 +11218,7 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, "rport in state 0x%x\n", ndlp->nlp_state); return; } - lpfc_printf_log(phba, KERN_ERR, - LOG_ELS | LOG_FCP_ERROR | LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3094 Start rport recovery on shost id 0x%x " "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " "flags 0x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 0dc1d56ff..070b9c7e1 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -35,8 +34,11 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -51,6 +53,9 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_debugfs.h" +#ifndef BUILD_BRCMFCOE +#include "lpfc_auth.h" +#endif /* AlpaArray for assignment of scsid for scan-down and bind_method */ static uint8_t lpfcAlpaArray[] = { @@ -158,17 +163,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "6789 rport name %llx != node port name %llx", - rport->port_name, - wwn_to_u64(ndlp->nlp_portname.u.wwn)); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6789 rport name %llx != node port name %llx", + rport->port_name, + wwn_to_u64(ndlp->nlp_portname.u.wwn)); evtp = &ndlp->dev_loss_evt; if (!list_empty(&evtp->evt_listp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "6790 rport name %llx dev_loss_evt pending", - rport->port_name); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6790 rport name %llx dev_loss_evt pending", + rport->port_name); return; } @@ -298,7 +303,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) } if (warn_on) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0203 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " "NPort x%06x Data: x%x x%x x%x\n", @@ -307,7 +312,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); } else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT, "0204 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " "NPort x%06x Data: x%x x%x x%x\n", @@ -520,6 +525,9 @@ lpfc_work_list_done(struct lpfc_hba *phba) { struct lpfc_work_evt *evtp = NULL; struct lpfc_nodelist *ndlp; +#ifndef BUILD_BRCMFCOE + struct lpfc_vport *vport = phba->pport; +#endif int free_evt; int fcf_inuse; uint32_t nlp_did; @@ -554,6 +562,26 @@ lpfc_work_list_done(struct lpfc_hba *phba) fcf_inuse, nlp_did); break; +#ifndef BUILD_BRCMFCOE + case LPFC_EVT_REAUTH: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + lpfc_auth_timeout_handler(vport, ndlp); + free_evt = 0; + /* decrement the node reference count held for + * this queued work + */ + lpfc_nlp_put(ndlp); + break; +#endif + case LPFC_EVT_RECOVER_PORT: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + lpfc_sli_abts_recover_port(ndlp->vport, ndlp); + free_evt = 0; + /* decrement the node reference count held for + * this queued work + */ + lpfc_nlp_put(ndlp); + break; case LPFC_EVT_ONLINE: if (phba->link_state < LPFC_LINK_DOWN) *(int *) (evtp->evt_arg1) = lpfc_online(phba); @@ -758,7 +786,7 @@ lpfc_do_work(void *p) || kthread_should_stop())); /* Signal wakeup shall terminate the worker thread */ if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0433 Wakeup on signal: rc=x%x\n", rc); break; } @@ -826,6 +854,13 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) if ((phba->sli_rev < LPFC_SLI_REV4) && (!remove && ndlp->nlp_type & NLP_FABRIC)) continue; +#ifndef BUILD_BRCMFCOE + else if ((phba->sli_rev == LPFC_SLI_REV4) && + (ndlp->nlp_type & NLP_FABRIC) && + (ndlp->dhc_cfg.state == LPFC_AUTH_SUCCESS)) + ndlp->dhc_cfg.state = LPFC_AUTH_UNKNOWN; +#endif + lpfc_disc_state_machine(vport, ndlp, NULL, remove ? NLP_EVT_DEVICE_RM @@ -844,6 +879,7 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) void lpfc_port_link_failure(struct lpfc_vport *vport) { + lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); /* Cleanup any outstanding received buffers */ @@ -1023,7 +1059,8 @@ lpfc_linkup_port(struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | - FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); + FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY | + FC_CT_CGN_RPA); vport->fc_flag |= FC_NDISC_ACTIVE; vport->fc_ns_retry = 0; spin_unlock_irq(shost->host_lock); @@ -1089,7 +1126,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { /* CLEAR_LA mbox error state */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0320 CLEAR_LA mbxStatus error x%x hba " "state x%x\n", mb->mbxStatus, vport->port_state); @@ -1209,7 +1246,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0306 CONFIG_LINK mbxStatus error x%x " "HBA state x%x\n", pmb->u.mb.mbxStatus, vport->port_state); @@ -1218,7 +1255,7 @@ sparam_out: lpfc_linkdown(phba); - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0200 CONFIG_LINK bad hba state x%x\n", vport->port_state); @@ -1254,10 +1291,10 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_vport *vport = mboxq->vport; if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2017 REG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2017 REG_FCFI mbxStatus error x%x " + "HBA state x%x\n", mboxq->u.mb.mbxStatus, + vport->port_state); goto fail_out; } @@ -1406,8 +1443,6 @@ __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, { struct lpfc_fcf_pri *fcf_pri; - lockdep_assert_held(&phba->hbalock); - fcf_pri = &phba->fcf.fcf_pri[fcf_index]; fcf_pri->fcf_rec.fcf_index = fcf_index; /* FCF record priority */ @@ -1492,8 +1527,6 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, struct fcf_record *new_fcf_record, uint32_t addr_mode, uint16_t vlan_id, uint32_t flag) { - lockdep_assert_held(&phba->hbalock); - /* Copy the fields from the HBA's FCF record */ lpfc_copy_fcf_record(fcf_rec, new_fcf_record); /* Update other fields of driver FCF record */ @@ -1830,7 +1863,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) * use through a sequence of @fcf_cnt eligible FCF records with equal * probability. To perform integer manunipulation of random numbers with * size unit32_t, the lower 16 bits of the 32-bit random number returned - * from prandom_u32() are taken as the random random number generated. + * from random32() are taken as the random random number generated. * * Returns true when outcome is for the newly read FCF record should be * chosen; otherwise, return false when outcome is for keeping the previously @@ -1842,7 +1875,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) uint32_t rand_num; /* Get 16-bit uniform random number */ - rand_num = 0xFFFF & prandom_u32(); + rand_num = (0xFFFF & prandom_u32()); /* Decision with probability 1/fcf_cnt */ if ((fcf_cnt * rand_num) < 0xFFFF) @@ -1880,7 +1913,7 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); if (unlikely(!mboxq->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2524 Failed to get the non-embedded SGE " "virtual address\n"); return NULL; @@ -1896,11 +1929,12 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (shdr_status || shdr_add_status) { if (shdr_status == STATUS_FCF_TABLE_EMPTY || if_type == LPFC_SLI_INTF_IF_TYPE_2) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2726 READ_FCF_RECORD Indicates empty " "FCF table.\n"); else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2521 READ_FCF_RECORD mailbox failed " "with status x%x add_status x%x, " "mbx\n", shdr_status, shdr_add_status); @@ -2278,7 +2312,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, &next_fcf_index); if (!new_fcf_record) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2765 Mailbox command READ_FCF_RECORD " "failed to retrieve a FCF record.\n"); /* Let next new FCF event trigger fast failover */ @@ -2322,7 +2356,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record, LPFC_FCOE_IGNORE_VID)) { if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) != phba->fcf.current_rec.fcf_indx) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2862 FCF (x%x) matches property " "of in-use FCF (x%x)\n", bf_get(lpfc_fcf_record_fcf_index, @@ -2392,7 +2427,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->pport->fc_flag); goto out; } else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2863 New FCF (x%x) matches " "property of in-use FCF (x%x)\n", bf_get(lpfc_fcf_record_fcf_index, @@ -2806,10 +2841,9 @@ lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0) && mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2891 Init VFI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2891 Init VFI mailbox failed 0x%x\n", + mboxq->u.mb.mbxStatus); mempool_free(mboxq, phba->mbox_mem_pool); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2837,7 +2871,7 @@ lpfc_issue_init_vfi(struct lpfc_vport *vport) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2892 Failed to allocate " + LOG_TRACE_EVENT, "2892 Failed to allocate " "init_vfi mailbox\n"); return; } @@ -2845,8 +2879,8 @@ lpfc_issue_init_vfi(struct lpfc_vport *vport) mboxq->mbox_cmpl = lpfc_init_vfi_cmpl; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2893 Failed to issue init_vfi mailbox\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2893 Failed to issue init_vfi mailbox\n"); mempool_free(mboxq, vport->phba->mbox_mem_pool); } } @@ -2866,10 +2900,9 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2609 Init VPI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2609 Init VPI mailbox failed 0x%x\n", + mboxq->u.mb.mbxStatus); mempool_free(mboxq, phba->mbox_mem_pool); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2883,7 +2916,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) lpfc_printf_vlog(vport, KERN_ERR, - LOG_DISCOVERY, + LOG_TRACE_EVENT, "2731 Cannot find fabric " "controller node\n"); else @@ -2896,7 +2929,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_initial_fdisc(vport); else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2606 No NPIV Fabric support\n"); } mempool_free(mboxq, phba->mbox_mem_pool); @@ -2919,8 +2952,7 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) if ((vport->port_type != LPFC_PHYSICAL_PORT) && (!vport->vpi)) { vpi = lpfc_alloc_vpi(vport->phba); if (!vpi) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3303 Failed to obtain vport vpi\n"); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2931,7 +2963,7 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2607 Failed to allocate " + LOG_TRACE_EVENT, "2607 Failed to allocate " "init_vpi mailbox\n"); return; } @@ -2940,8 +2972,8 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) mboxq->mbox_cmpl = lpfc_init_vpi_cmpl; rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2608 Failed to issue init_vpi mailbox\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2608 Failed to issue init_vpi mailbox\n"); mempool_free(mboxq, vport->phba->mbox_mem_pool); } } @@ -2985,7 +3017,7 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) lpfc_vport_set_state(vports[i], FC_VPORT_NO_FABRIC_SUPP); lpfc_printf_vlog(vports[i], KERN_ERR, - LOG_ELS, + LOG_TRACE_EVENT, "0259 No NPIV " "Fabric support\n"); } @@ -3000,6 +3032,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_dmabuf *dmabuf = mboxq->ctx_buf; struct lpfc_vport *vport = mboxq->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); +#ifndef BUILD_BRCMFCOE + struct lpfc_nodelist *ndlp; + int rc; +#endif /* * VFI not supported for interface type 0, so ignore any mailbox @@ -3009,10 +3045,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0) && mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2018 REG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2018 REG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* FLOGI failed, use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); @@ -3072,6 +3108,13 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) else lpfc_disc_start(vport); } else { +#ifndef BUILD_BRCMFCOE + ndlp = lpfc_findnode_did(vport, Fabric_DID); + rc = lpfc_auth_start(vport, ndlp); + if (!rc) + goto out_free_mem; + +#endif lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); } @@ -3099,7 +3142,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if (mb->mbxStatus) { /* READ_SPARAM mbox error state */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0319 READ_SPARAM mbxStatus error x%x " "hba state x%x>\n", mb->mbxStatus, vport->port_state); @@ -3107,8 +3150,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto out; } - memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt, - sizeof (struct serv_parm)); + memcpy((uint8_t *)sp, (uint8_t *)mp->virt, sizeof(struct serv_parm)); ed_tov = be32_to_cpu(sp->cmn.e_d_tov); if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ @@ -3316,7 +3358,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) GFP_KERNEL); if (unlikely(!fcf_record)) { lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "2554 Could not allocate memory for " "fcf record\n"); rc = -ENODEV; @@ -3328,7 +3370,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) rc = lpfc_sli4_add_fcf_record(phba, fcf_record); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "2013 Could not manually add FCF " "record 0, status %d\n", rc); rc = -ENODEV; @@ -3370,7 +3412,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) return; out: lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0263 Discovery Mailbox error: state: 0x%x : x%px x%px\n", vport->port_state, sparam_mbox, cfglink_mbox); lpfc_issue_clear_la(phba, vport); @@ -3492,8 +3534,12 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->wait_4_mlo_maint_flg); } lpfc_mbx_process_link_up(phba, la); - } else if (attn_type == LPFC_ATT_LINK_DOWN || - attn_type == LPFC_ATT_UNEXP_WWPN) { + + if (phba->cmf_active_mode != LPFC_CFG_OFF) + lpfc_cmf_signal_init(phba); + + } else if ((attn_type == LPFC_ATT_LINK_DOWN) || + (attn_type == LPFC_ATT_UNEXP_WWPN)) { phba->fc_stat.LinkDown++; if (phba->link_flag & LS_LOOPBACK_MODE) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, @@ -3504,8 +3550,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->pport->port_state, vport->fc_flag); else if (attn_type == LPFC_ATT_UNEXP_WWPN) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1313 Link Down UNEXP WWPN Event x%x received " - "Data: x%x x%x x%x x%x x%x\n", + "1313 Link Down Unexpected FA WWPN Event x%x " + "received Data: x%x x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_mm, la), @@ -3520,8 +3566,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) bf_get(lpfc_mbx_read_top_fa, la)); lpfc_mbx_issue_link_down(phba); } - if (phba->sli.sli_flag & LPFC_MENLO_MAINT && - attn_type == LPFC_ATT_LINK_UP) { + if ((phba->sli.sli_flag & LPFC_MENLO_MAINT) && + (attn_type == LPFC_ATT_LINK_UP)) { if (phba->link_state != LPFC_LINK_DOWN) { phba->fc_stat.LinkDown++; lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, @@ -3643,7 +3689,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) break; /* If VPI is busy, reset the HBA */ case 0x9700: - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", vport->vpi, mb->mbxStatus); if (!(phba->pport->load_flag & FC_UNLOADING)) @@ -3681,7 +3727,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1800 Could not issue unreg_vpi\n"); mempool_free(mbox, phba->mbox_mem_pool); vport->unreg_vpi_cmpl = VPORT_ERROR; @@ -3768,7 +3814,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0542 lpfc_create_static_vport failed to" " allocate mailbox memory\n"); return; @@ -3778,7 +3824,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); if (!vport_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0543 lpfc_create_static_vport failed to" " allocate vport_info\n"); mempool_free(pmb, phba->mbox_mem_pool); @@ -3839,11 +3885,12 @@ lpfc_create_static_vport(struct lpfc_hba *phba) if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) || ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK) != VPORT_INFO_REV)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0545 lpfc_create_static_vport bad" - " information header 0x%x 0x%x\n", - le32_to_cpu(vport_info->signature), - le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0545 lpfc_create_static_vport bad" + " information header 0x%x 0x%x\n", + le32_to_cpu(vport_info->signature), + le32_to_cpu(vport_info->rev) & + VPORT_INFO_REV_MASK); goto out; } @@ -3907,7 +3954,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->ctx_buf = NULL; if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0258 Register Fabric login error: 0x%x\n", mb->mbxStatus); lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -3966,11 +4013,18 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } - /* - * This routine will issue a GID_FT for each FC4 Type supported - * by the driver. ALL GID_FTs must complete before discovery is started. - */ -int +/** + * lpfc_issue_gidft - issue a GID_FT for each FC4 Type supported by the driver + * @vport: The virtual port for which this call is being executed. + * + * This routine will issue a GID_FT for each FC4 Type supported by the driver. + * ALL GID_FTs must complete before discovery is started. + * + * Return value : + * 0 - Failure to issue a GID_FT + * n - Count of GID_FTs issued outstanding + **/ +uint32_t lpfc_issue_gidft(struct lpfc_vport *vport) { /* Good status, issue CT Request to NameServer */ @@ -3980,7 +4034,8 @@ lpfc_issue_gidft(struct lpfc_vport *vport) /* Cannot issue NameServer FCP Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0604 %s FC TYPE %x %s\n", "Failed to issue GID_FT to ", FC_TYPE_FCP, @@ -3996,7 +4051,8 @@ lpfc_issue_gidft(struct lpfc_vport *vport) /* Cannot issue NameServer NVME Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0605 %s FC_TYPE %x %s %d\n", "Failed to issue GID_FT to ", FC_TYPE_NVME, @@ -4020,7 +4076,7 @@ lpfc_issue_gidft(struct lpfc_vport *vport) * 0 - Failure to issue a GID_PT * 1 - GID_PT issued **/ -int +uint32_t lpfc_issue_gidpt(struct lpfc_vport *vport) { /* Good status, issue CT Request to NameServer */ @@ -4028,7 +4084,7 @@ lpfc_issue_gidpt(struct lpfc_vport *vport) /* Cannot issue NameServer FCP Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0606 %s Port TYPE %x %s\n", "Failed to issue GID_PT to ", GID_PT_N_PORT, @@ -4052,13 +4108,14 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; struct lpfc_vport *vport = pmb->vport; + int rc; pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; vport->gidft_inp = 0; if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0260 Register NameServer error: 0x%x\n", mb->mbxStatus); @@ -4094,7 +4151,7 @@ out: ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), @@ -4117,7 +4174,25 @@ out: FC_TYPE_NVME); /* Issue SCR just before NameServer GID_FT Query */ - lpfc_issue_els_scr(vport, SCR_DID, 0); + lpfc_issue_els_scr(vport, 0); + + /* Link was bounced or a Fabric LOGO occurred. Start EDC + * with initial FW values provided the congestion mode is + * not off. Note that signals may or may not be supported + * by the adapter but FPIN is provided by default for 1 + * or both missing signals support. + */ + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + phba->cgn_reg_fpin = phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = phba->cgn_init_reg_signal; + rc = lpfc_issue_els_edc(vport, 0); + lpfc_printf_log(phba, KERN_INFO, + LOG_INIT | LOG_ELS | LOG_DISCOVERY, + "4220 EDC issue error x%x, Data: x%x\n", + rc, phba->cgn_init_reg_signal); + } else { + lpfc_issue_els_rdf(vport, 0); + } } vport->fc_ns_retry = 0; @@ -4186,6 +4261,9 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (vport->load_flag & FC_UNLOADING) return; + if (ndlp->nlp_flag & NLP_EXTERNAL_DIF) + lpfc_edsm_validate_target(vport, ndlp); + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, @@ -4200,15 +4278,9 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rdata->pnode = lpfc_nlp_get(ndlp); if (ndlp->nlp_type & NLP_FCP_TARGET) - rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; + rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; if (ndlp->nlp_type & NLP_FCP_INITIATOR) - rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; - if (ndlp->nlp_type & NLP_NVME_INITIATOR) - rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR; - if (ndlp->nlp_type & NLP_NVME_TARGET) - rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET; - if (ndlp->nlp_type & NLP_NVME_DISCOVERY) - rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY; + rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); @@ -4221,6 +4293,32 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; } + + lpfc_throttle_vlog(ndlp->vport, &ndlp->log, LOG_NODE, + "3237 SCSI ID %d " + " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, " + " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ndlp->nlp_sid, + ndlp->nlp_nodename.u.wwn[0], + ndlp->nlp_nodename.u.wwn[1], + ndlp->nlp_nodename.u.wwn[2], + ndlp->nlp_nodename.u.wwn[3], + ndlp->nlp_nodename.u.wwn[4], + ndlp->nlp_nodename.u.wwn[5], + ndlp->nlp_nodename.u.wwn[6], + ndlp->nlp_nodename.u.wwn[7], + ndlp->nlp_portname.u.wwn[0], + ndlp->nlp_portname.u.wwn[1], + ndlp->nlp_portname.u.wwn[2], + ndlp->nlp_portname.u.wwn[3], + ndlp->nlp_portname.u.wwn[4], + ndlp->nlp_portname.u.wwn[5], + ndlp->nlp_portname.u.wwn[6], + ndlp->nlp_portname.u.wwn[7]); + +#ifndef NO_APEX + lpfc_set_ndlps_fcp_priority(ndlp); +#endif return; } @@ -4229,6 +4327,8 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; struct lpfc_vport *vport = ndlp->vport; + struct lpfc_external_dif_support *dp; + unsigned long flags; if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) return; @@ -4243,6 +4343,22 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) fc_remote_port_delete(rport); + /* + * Cleanup all External DIF paths that match this ndlp. + * They will need to be revalidated if the NPort comes back. + */ + if (ndlp->nlp_flag & NLP_EXTERNAL_DIF) { + + spin_lock_irqsave(&vport->external_dif_lock, flags); + list_for_each_entry(dp, &vport->external_dif_list, listentry) { + if (memcmp(&ndlp->nlp_portname, + (uint8_t *)&dp->portName, + sizeof(struct lpfc_name)) == 0) + lpfc_edsm_set_state(vport, dp, + LPFC_EDSM_NEEDS_INQUIRY); + } + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + } return; } @@ -4303,6 +4419,10 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* FCP and NVME Transport interface */ if ((old_state == NLP_STE_MAPPED_NODE || old_state == NLP_STE_UNMAPPED_NODE)) { + /* SCSI-FCP first burst needs to be renegotiated on the + * next successful PRLI completion. + */ + ndlp->first_burst = 0; if (ndlp->rport) { vport->phba->nport_event_cnt++; lpfc_unregister_remote_port(ndlp); @@ -4368,7 +4488,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, GFP_KERNEL); if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0286 lpfc_nlp_state_cleanup failed to " "allocate statistical data buffer DID " "0x%x\n", ndlp->nlp_DID); @@ -4422,8 +4542,8 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, char name1[16], name2[16]; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0904 NPort state transition x%06x, %s -> %s\n", - ndlp->nlp_DID, + "0904 NPort state transition %p x%06x x%x: %s -> %s\n", + ndlp, ndlp->nlp_DID, ndlp->nlp_flag, lpfc_nlp_state_name(name1, sizeof(name1), old_state), lpfc_nlp_state_name(name2, sizeof(name2), state)); @@ -4507,7 +4627,25 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, + (unsigned long)ndlp); +#else timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0); +#endif + +#ifndef BUILD_BRCMFCOE + INIT_LIST_HEAD(&ndlp->reauth_evt.evt_listp); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&ndlp->dhc_cfg.nlp_reauthfunc, lpfc_auth_reauth, + (unsigned long)ndlp); +#else + timer_setup(&ndlp->dhc_cfg.nlp_reauthfunc, lpfc_auth_reauth, + 0); +#endif +#endif + INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp); + ndlp->nlp_DID = did; ndlp->vport = vport; ndlp->phba = vport->phba; @@ -4576,7 +4714,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* First preserve the orginal DID, xri_bitmap and some flags */ did = ndlp->nlp_DID; - flag = (ndlp->nlp_flag & NLP_UNREG_INP); + flag = (ndlp->nlp_flag & (NLP_EXTERNAL_DIF | NLP_UNREG_INP)); if (flag & NLP_UNREG_INP) defer_did = ndlp->nlp_defer_did; if (phba->sli_rev == LPFC_SLI_REV4) @@ -4623,8 +4761,10 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp; free_rpi: - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev == LPFC_SLI_REV4) { lpfc_sli4_free_rpi(vport->phba, rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + } return NULL; } @@ -4883,6 +5023,7 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } ndlp->nlp_flag &= ~NLP_UNREG_INP; } @@ -4946,7 +5087,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_flag & NLP_RPI_REGISTERED || ndlp->nlp_flag & NLP_REG_LOGIN_SEND) { if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "3366 RPI x%x needs to be " "unregistered nlp_flag x%x " "did x%x\n", @@ -4957,7 +5099,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * no need to queue up another one. */ if (ndlp->nlp_flag & NLP_UNREG_INP) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "1436 unreg_rpi SKIP UNREG x%x on " "NPort x%x deferred x%x flg x%x " "Data: x%px\n", @@ -4987,7 +5130,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (!(vport->fc_flag & FC_OFFLINE_MODE))) ndlp->nlp_flag |= NLP_UNREG_INP; - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "1433 unreg_rpi UNREG x%x on " "NPort x%x deferred flg x%x " "Data:x%px\n", @@ -4999,6 +5143,29 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; } + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "1444 Failed to allocate mempool " + "unreg_rpi UNREG x%x, " + "DID x%x, flag x%x, " + "ndlp x%px\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp); + + /* Because mempool_alloc failed, we + * will issue a LOGO here and keep the rpi alive if + * not unloading. + */ + if (!(vport->load_flag & FC_UNLOADING)) { + ndlp->nlp_flag &= ~NLP_UNREG_INP; + lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_NPR_NODE); + } + + return 1; } lpfc_no_rpi(phba, ndlp); out: @@ -5031,8 +5198,8 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (!vports) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2884 Vport array allocation failed \n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2884 Vport array allocation failed \n"); return; } for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { @@ -5075,9 +5242,10 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport) mempool_free(mbox, phba->mbox_mem_pool); if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1836 Could not issue " - "unreg_login(all_rpis) status %d\n", rc); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "1836 Could not issue " + "unreg_login(all_rpis) status %d\n", + rc); } } @@ -5104,7 +5272,7 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) mempool_free(mbox, phba->mbox_mem_pool); if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1815 Could not issue " "unreg_did (default rpis) status %d\n", rc); @@ -5201,6 +5369,13 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->dev_loss_evt.evt_listp); + +#ifndef BUILD_BRCMFCOE + del_timer_sync(&ndlp->dhc_cfg.nlp_reauthfunc); + list_del_init(&ndlp->reauth_evt.evt_listp); +#endif + list_del_init(&ndlp->recovery_evt.evt_listp); + lpfc_cleanup_vports_rrqs(vport, ndlp); if (phba->sli_rev == LPFC_SLI_REV4) ndlp->nlp_flag |= NLP_RELEASE_RPI; @@ -5239,12 +5414,14 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if ((ndlp->nlp_flag & NLP_DEFER_RM) && !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && !(ndlp->nlp_flag & NLP_RPI_REGISTERED) && - phba->sli_rev != LPFC_SLI_REV4) { + (phba->sli_rev != LPFC_SLI_REV4)) { /* For this case we need to cleanup the default rpi * allocated by the firmware. */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0005 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x " + "ref %d map:x%x ndlp x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -5281,8 +5458,9 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, "0940 removed node x%px DID x%x " - " rport not null x%px\n", - ndlp, ndlp->nlp_DID, ndlp->rport); + "rpi %d rport not null x%px\n", + ndlp, ndlp->nlp_DID, ndlp->nlp_rpi, + ndlp->rport); rport = ndlp->rport; rdata = rport->dd_data; rdata->pnode = NULL; @@ -5375,19 +5553,6 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) return NULL; } -struct lpfc_nodelist * -lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - unsigned long iflags; - - spin_lock_irqsave(shost->host_lock, iflags); - ndlp = __lpfc_findnode_did(vport, did); - spin_unlock_irqrestore(shost->host_lock, iflags); - return ndlp; -} - struct lpfc_nodelist * lpfc_findnode_mapped(struct lpfc_vport *vport) { @@ -5423,6 +5588,19 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) return NULL; } +struct lpfc_nodelist * +lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + unsigned long iflags; + + spin_lock_irqsave(shost->host_lock, iflags); + ndlp = __lpfc_findnode_did(vport, did); + spin_unlock_irqrestore(shost->host_lock, iflags); + return ndlp; +} + struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { @@ -5440,6 +5618,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (!ndlp) return NULL; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6453 Setup New Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -5453,6 +5638,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) "0014 Could not enable ndlp\n"); return NULL; } + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6454 Setup Enabled Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -5472,6 +5663,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) */ lpfc_cancel_retry_delay_tmo(vport, ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6455 Setup RSCN Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + /* NVME Target mode waits until rport is known to be * impacted by the RSCN before it transitions. No * active management - just go to NPR provided the @@ -5494,9 +5691,21 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); - } else + } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6456 Skip Setup RSCN Node x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); ndlp = NULL; + } } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6457 Setup Active Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + /* If the initiator received a PLOGI from this NPort or if the * initiator is already in the process of discovery on it, * there's no need to try to discover it again. @@ -5648,10 +5857,10 @@ lpfc_disc_start(struct lpfc_vport *vport) /* Start Discovery state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0202 Start Discovery hba state x%x " - "Data: x%x x%x x%x\n", + "0202 Start Discovery port state x%x " + "flg x%x Data: x%x x%x x%x\n", vport->port_state, vport->fc_flag, vport->fc_plogi_cnt, - vport->fc_adisc_cnt); + vport->fc_adisc_cnt, vport->fc_npr_cnt); /* First do ADISCs - if any */ num_sent = lpfc_els_disc_adisc(vport); @@ -5760,6 +5969,9 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } spin_unlock_irq(&phba->hbalock); + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); @@ -5808,9 +6020,17 @@ lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) */ /*****************************************************************************/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_disc_timeout(unsigned long ptr) +#else lpfc_disc_timeout(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_vport *vport = (struct lpfc_vport *) ptr; +#else struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo); +#endif struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long flags = 0; @@ -5891,7 +6111,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0222 Initial %s timeout\n", vport->vpi ? "FDISC" : "FLOGI"); @@ -5909,7 +6130,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FABRIC_CFG_LINK: /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for NameServer login */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0223 Timeout while waiting for " "NameServer login\n"); /* Next look for NameServer ndlp */ @@ -5922,7 +6144,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0224 NameServer Query timeout " "Data: x%x x%x\n", vport->fc_ns_retry, LPFC_MAX_NS_RETRY); @@ -5931,8 +6154,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Try it one more time */ vport->fc_ns_retry++; vport->gidft_inp = 0; - rc = lpfc_issue_gidft(vport); - if (rc == 0) + if (lpfc_issue_gidft(vport) != 0) break; } vport->fc_ns_retry = 0; @@ -5955,7 +6177,8 @@ restart_disc: /* Setup and issue mailbox INITIALIZE LINK command */ initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0206 Device Discovery " "completion error\n"); phba->link_state = LPFC_HBA_ERROR; @@ -5977,7 +6200,8 @@ restart_disc: case LPFC_DISC_AUTH: /* Node Authentication timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0227 Node Authentication timeout\n"); lpfc_disc_flush_list(vport); @@ -5997,7 +6221,8 @@ restart_disc: case LPFC_VPORT_READY: if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0231 RSCN timeout Data: x%x " "x%x\n", vport->fc_ns_retry, LPFC_MAX_NS_RETRY); @@ -6011,7 +6236,8 @@ restart_disc: break; default: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0273 Unexpected discovery timeout, " "vport State x%x\n", vport->port_state); break; @@ -6020,7 +6246,8 @@ restart_disc: switch (phba->link_state) { case LPFC_CLEAR_LA: /* CLEAR LA timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0228 CLEAR LA timeout\n"); clrlaerr = 1; break; @@ -6034,7 +6261,8 @@ restart_disc: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0230 Unexpected timeout, hba link " "state x%x\n", phba->link_state); clrlaerr = 1; @@ -6079,7 +6307,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), @@ -6090,10 +6318,12 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * DHBA -> DPRT -> RHBA -> RPA (physical port) * DPRT -> RPRT (vports) */ - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT) { + vport->fc_flag &= ~FC_CT_CGN_RPA; /* For extra ELXE2EM RPA */ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); - else + } else { lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0); + } /* decrement the node reference count held for this callback @@ -6130,17 +6360,19 @@ static struct lpfc_nodelist * __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) { struct lpfc_nodelist *ndlp; + uint32_t data1; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (filter(ndlp, param)) { + data1 = (((uint32_t) ndlp->nlp_state << 24) | + ((uint32_t) ndlp->nlp_xri << 16) | + ((uint32_t) ndlp->nlp_type << 8) | + ((uint32_t) ndlp->nlp_rpi & 0xff)); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "3185 FIND node filter %ps DID " - "ndlp x%px did x%x flg x%x st x%x " - "xri x%x type x%x rpi x%x\n", + "Data: x%px x%x x%x x%x\n", filter, ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_xri, ndlp->nlp_type, - ndlp->nlp_rpi); + ndlp->nlp_flag, data1); return ndlp; } } @@ -6219,15 +6451,15 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) * Translate the physical vpi to the logical vpi. The * vport stores the logical vpi. */ - for (i = 0; i < phba->max_vpi; i++) { + for (i = 0; i <= phba->max_vpi; i++) { if (vpi == phba->vpi_ids[i]) break; } - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); + if (i > phba->max_vpi) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2936 Could not find Vport mapped " + "to vpi %d\n", vpi); return NULL; } } @@ -6268,12 +6500,12 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0007 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, + "0007 Init New ndlp x%px, rpi:x%x DID:%x " + "flg:x%x refcnt:%d map:x%x\n", + ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, kref_read(&ndlp->kref), + ndlp->nlp_usg_map); ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, @@ -6502,7 +6734,8 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) goto out; } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { ret = 1; - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "2624 RPI %x DID %x flag %x " "still logged in\n", ndlp->nlp_rpi, ndlp->nlp_DID, @@ -6530,10 +6763,10 @@ lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2555 UNREG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2555 UNREG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); } spin_lock_irq(shost->host_lock); phba->pport->fc_flag &= ~FC_VFI_REGISTERED; @@ -6555,10 +6788,10 @@ lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_vport *vport = mboxq->vport; if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2550 UNREG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2550 UNREG_FCFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); } mempool_free(mboxq, phba->mbox_mem_pool); return; @@ -6647,7 +6880,7 @@ lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2551 UNREG_FCFI mbox allocation failed" "HBA state x%x\n", phba->pport->port_state); return -ENOMEM; @@ -6658,7 +6891,7 @@ lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2552 Unregister FCFI command failed rc x%x " "HBA state x%x\n", rc, phba->pport->port_state); @@ -6682,7 +6915,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) /* Preparation for unregistering fcf */ rc = lpfc_unregister_fcf_prep(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2748 Failed to prepare for unregistering " "HBA's FCF record: rc=%d\n", rc); return; @@ -6718,7 +6951,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_INIT_DISC; spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2553 lpfc_unregister_unused_fcf failed " "to read FCF record HBA state x%x\n", phba->pport->port_state); @@ -6740,7 +6973,7 @@ lpfc_unregister_fcf(struct lpfc_hba *phba) /* Preparation for unregistering fcf */ rc = lpfc_unregister_fcf_prep(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2749 Failed to prepare for unregistering " "HBA's FCF record: rc=%d\n", rc); return; @@ -6827,9 +7060,9 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), GFP_KERNEL); if (!conn_entry) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2566 Failed to allocate connection" - " table entry\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2566 Failed to allocate connection" + " table entry\n"); return; } @@ -6973,7 +7206,7 @@ lpfc_parse_fcoe_conf(struct lpfc_hba *phba, /* Check the region signature first */ if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2567 Config region 23 has bad signature\n"); return; } @@ -6982,8 +7215,8 @@ lpfc_parse_fcoe_conf(struct lpfc_hba *phba, /* Check the data structure version */ if (buff[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2568 Config region 23 has bad version\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2568 Config region 23 has bad version\n"); return; } offset += 4; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index b5642c872..af1abc9d0 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -22,7 +22,7 @@ #define FDMI_DID 0xfffffaU #define NameServer_DID 0xfffffcU -#define SCR_DID 0xfffffdU +#define Fabric_Cntl_DID 0xfffffdU #define Fabric_DID 0xfffffeU #define Bcast_DID 0xffffffU #define Mask_DID 0xffffffU @@ -404,7 +404,8 @@ struct csp { uint16_t huntgroup:1; /* FC Word 1, bit 23 */ uint16_t simplex:1; /* FC Word 1, bit 22 */ - uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ + uint16_t fcsp:1; /* FC Word 1, bit 21 */ + uint16_t word1Reserved1:2; /* FC Word 1, bit 20:19 */ uint16_t dhd:1; /* FC Word 1, bit 18 */ uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ uint16_t payloadlength:1; /* FC Word 1, bit 16 */ @@ -421,7 +422,8 @@ struct csp { uint16_t payloadlength:1; /* FC Word 1, bit 16 */ uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ uint16_t dhd:1; /* FC Word 1, bit 18 */ - uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ + uint16_t word1Reserved1:2; /* FC Word 1, bit 20:19 */ + uint16_t fcsp:1; /* FC Word 1, bit 21 */ uint16_t simplex:1; /* FC Word 1, bit 22 */ uint16_t huntgroup:1; /* FC Word 1, bit 23 */ #endif @@ -560,10 +562,10 @@ struct fc_vft_header { #define fc_vft_hdr_hopct_WORD word1 }; -#include - /* * Extended Link Service LS_COMMAND codes (Payload Word 0) + * The supported payload size is also hard-coded into this word + * when necessary. */ #ifdef __BIG_ENDIAN_BITFIELD #define ELS_CMD_MASK 0xffff0000 @@ -587,7 +589,10 @@ struct fc_vft_header { #define ELS_CMD_TEST 0x11000000 #define ELS_CMD_RRQ 0x12000000 #define ELS_CMD_REC 0x13000000 +#define ELS_CMD_FPIN 0x16000000 +#define ELS_CMD_EDC 0x17000000 #define ELS_CMD_RDP 0x18000000 +#define ELS_CMD_RDF 0x19000000 #define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_NVMEPRLI 0x20140018 #define ELS_CMD_PRLO 0x21100014 @@ -597,16 +602,16 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52000000 #define ELS_CMD_FARP 0x54000000 #define ELS_CMD_FARPR 0x55000000 -#define ELS_CMD_RPS 0x56000000 #define ELS_CMD_RPL 0x57000000 #define ELS_CMD_FAN 0x60000000 -#define ELS_CMD_RSCN 0x61040000 #define ELS_CMD_RSCN_XMT 0x61040008 +#define ELS_CMD_RSCN 0x61040000 #define ELS_CMD_SCR 0x62000000 #define ELS_CMD_RNID 0x78000000 #define ELS_CMD_LIRR 0x7A000000 #define ELS_CMD_LCB 0x81000000 -#define ELS_CMD_FPIN 0x16000000 +#define ELS_CMD_AUTH 0x90000000 +#define ELS_CMD_RAW 0xff000000 #else /* __LITTLE_ENDIAN_BITFIELD */ #define ELS_CMD_MASK 0xffff #define ELS_RSP_MASK 0xff @@ -629,7 +634,14 @@ struct fc_vft_header { #define ELS_CMD_TEST 0x11 #define ELS_CMD_RRQ 0x12 #define ELS_CMD_REC 0x13 +#if defined(FCH_EVT_LINK_FPIN) +#define ELS_CMD_FPIN ELS_FPIN +#else +#define ELS_CMD_FPIN 0x16 +#endif +#define ELS_CMD_EDC 0x17 #define ELS_CMD_RDP 0x18 +#define ELS_CMD_RDF 0x19 #define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_NVMEPRLI 0x18001420 #define ELS_CMD_PRLO 0x14001021 @@ -639,16 +651,16 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52 #define ELS_CMD_FARP 0x54 #define ELS_CMD_FARPR 0x55 -#define ELS_CMD_RPS 0x56 #define ELS_CMD_RPL 0x57 #define ELS_CMD_FAN 0x60 -#define ELS_CMD_RSCN 0x0461 #define ELS_CMD_RSCN_XMT 0x08000461 +#define ELS_CMD_RSCN 0x0461 #define ELS_CMD_SCR 0x62 #define ELS_CMD_RNID 0x78 #define ELS_CMD_LIRR 0x7A #define ELS_CMD_LCB 0x81 -#define ELS_CMD_FPIN ELS_FPIN +#define ELS_CMD_AUTH 0x90 +#define ELS_CMD_RAW 0xff #endif /* @@ -919,24 +931,6 @@ typedef struct _RNID { /* Structure is in Big Endian format */ } un; } __packed RNID; -typedef struct _RPS { /* Structure is in Big Endian format */ - union { - uint32_t portNum; - struct lpfc_name portName; - } un; -} RPS; - -typedef struct _RPS_RSP { /* Structure is in Big Endian format */ - uint16_t rsvd1; - uint16_t portStatus; - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; -} RPS_RSP; - struct RLS { /* Structure is in Big Endian format */ uint32_t rls; #define rls_rsvd_SHIFT 24 @@ -1099,6 +1093,11 @@ struct fc_lcb_res_frame { uint16_t lcb_duration; /* LCB Payload Word 2, bit 15:0 */ }; +struct fc_RSCN { /* RSCN ELS frame */ +#define RSCN_EQ_PORT_ATTRIBUTE 2 + uint32_t NPort_ID; +}; + /* * Read Diagnostic Parameters (RDP) ELS frame. */ @@ -1398,6 +1397,9 @@ struct lpfc_fdmi_reg_hba { struct lpfc_fdmi_reg_port_list rpl; }; +/******** E2E ********/ +#define SLI_CT_E2E_Subtypes 0x11 + /* * Register HBA Attributes (RHAT) */ @@ -1501,6 +1503,7 @@ struct lpfc_fdmi_reg_portattr { #define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */ #define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */ #define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */ +#define RPRT_VENDOR_CGN 0xf047 /* canned ASCII string */ #define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */ #define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */ #define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */ @@ -1533,6 +1536,7 @@ struct lpfc_fdmi_reg_portattr { #define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */ +#define LPFC_FDMI_VENDOR_ATTR_cgn 0x00800000 /* Vendor specific */ /* Bit mask for FDMI-1 defined PORT attributes */ #define LPFC_FDMI1_PORT_ATTR 0x0000003f @@ -1587,8 +1591,10 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_PROTEUS_PF 0xe180 #define PCI_DEVICE_ID_LANCER_FC 0xe200 #define PCI_DEVICE_ID_LANCER_FC_VF 0xe208 +#ifndef BUILD_RHEL8 #define PCI_DEVICE_ID_LANCER_FCOE 0xe260 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 +#endif #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 #define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 #define PCI_DEVICE_ID_SAT_SMB 0xf011 @@ -3280,8 +3286,7 @@ typedef struct { #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 : 19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd1 : 20; /* Reserved */ uint32_t casabt : 1; /* Configure async abts status notice */ uint32_t rsvd2 : 2; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ @@ -3305,12 +3310,10 @@ typedef struct { uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t rsvd2 : 2; /* Reserved */ uint32_t casabt : 1; /* Configure async abts status notice */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd1 : 19; /* Reserved */ + uint32_t rsvd1 : 20; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 : 19; /* Reserved */ - uint32_t gdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 : 20; /* Reserved */ uint32_t gasabt : 1; /* Grant async abts status notice */ uint32_t rsvd4 : 2; /* Reserved */ uint32_t gbg : 1; /* Grant BlockGuard */ @@ -3334,8 +3337,7 @@ typedef struct { uint32_t gbg : 1; /* Grant BlockGuard */ uint32_t rsvd4 : 2; /* Reserved */ uint32_t gasabt : 1; /* Grant async abts status notice */ - uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 : 19; /* Reserved */ + uint32_t rsvd3 : 20; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD @@ -3357,15 +3359,11 @@ typedef struct { uint32_t rsvd6; /* Reserved */ #ifdef __BIG_ENDIAN_BITFIELD - uint32_t fips_rev : 3; /* FIPS Spec Revision */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t sec_err : 9; /* security crypto error */ + uint32_t rsvd7 : 16; uint32_t max_vpi : 16; /* Max number of virt N-Ports */ #else /* __LITTLE_ENDIAN */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ - uint32_t sec_err : 9; /* security crypto error */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t fips_rev : 3; /* FIPS Spec Revision */ + uint32_t rsvd7 : 16; #endif } CONFIG_PORT_VAR; diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index b8a772f80..de23721aa 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -20,6 +20,9 @@ * included with this package. * *******************************************************************/ +#include +#include + /* Macros to deal with bit fields. Each bit field must have 3 #defines * associated with it (_SHIFT, _MASK, and _WORD). * EG. For a bit field that is in the 7th bit of the "field4" field of a @@ -122,7 +125,6 @@ struct lpfc_sli_intf { /* Define SLI4 Alignment requirements. */ #define LPFC_ALIGN_16_BYTE 16 #define LPFC_ALIGN_64_BYTE 64 -#define SLI4_PAGE_SIZE 4096 /* Define SLI4 specific definitions. */ #define LPFC_MQ_CQE_BYTE_OFFSET 256 @@ -211,7 +213,6 @@ struct lpfc_sli_intf { #define LPFC_MAX_IMAX 5000000 #define LPFC_DEF_IMAX 0 -#define LPFC_IMAX_THRESHOLD 1000 #define LPFC_MAX_AUTO_EQ_DELAY 120 #define LPFC_EQ_DELAY_STEP 15 #define LPFC_EQD_ISR_TRIGGER 20000 @@ -389,6 +390,12 @@ struct lpfc_wcqe_complete { #define lpfc_wcqe_c_ersp0_MASK 0x0000FFFF #define lpfc_wcqe_c_ersp0_WORD word0 uint32_t total_data_placed; +#define lpfc_wcqe_c_cmf_cg_SHIFT 31 +#define lpfc_wcqe_c_cmf_cg_MASK 0x00000001 +#define lpfc_wcqe_c_cmf_cg_WORD total_data_placed +#define lpfc_wcqe_c_cmf_bw_SHIFT 0 +#define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF +#define lpfc_wcqe_c_cmf_bw_WORD total_data_placed uint32_t parameter; #define lpfc_wcqe_c_bg_edir_SHIFT 5 #define lpfc_wcqe_c_bg_edir_MASK 0x00000001 @@ -650,6 +657,9 @@ struct lpfc_register { #define lpfc_sliport_status_oti_SHIFT 29 #define lpfc_sliport_status_oti_MASK 0x1 #define lpfc_sliport_status_oti_WORD word0 +#define lpfc_sliport_status_dip_SHIFT 25 +#define lpfc_sliport_status_dip_MASK 0x1 +#define lpfc_sliport_status_dip_WORD word0 #define lpfc_sliport_status_rn_SHIFT 24 #define lpfc_sliport_status_rn_MASK 0x1 #define lpfc_sliport_status_rn_WORD word0 @@ -680,6 +690,7 @@ struct lpfc_register { #define lpfc_sliport_eqdelay_id_MASK 0xfff #define lpfc_sliport_eqdelay_id_WORD word0 #define LPFC_SEC_TO_USEC 1000000 +#define LPFC_SEC_TO_MSEC 1000 /* The following Registers apply to SLI4 if_type 0 UCNAs. They typically * reside in BAR 2. @@ -952,6 +963,12 @@ union lpfc_sli4_cfg_shdr { #define lpfc_mbox_hdr_add_status_SHIFT 8 #define lpfc_mbox_hdr_add_status_MASK 0x000000FF #define lpfc_mbox_hdr_add_status_WORD word7 +#define LPFC_ADD_STATUS_INCOMPAT_OBJ 0xA2 +#define lpfc_mbox_hdr_add_status_2_SHIFT 16 +#define lpfc_mbox_hdr_add_status_2_MASK 0x000000FF +#define lpfc_mbox_hdr_add_status_2_WORD word7 +#define LPFC_ADD_STATUS_2_INCOMPAT_FLASH 0x01 +#define LPFC_ADD_STATUS_2_INCORRECT_ASIC 0x02 uint32_t response_length; uint32_t actual_response_length; } response; @@ -1008,6 +1025,7 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_SET_HOST_DATA 0x5D #define LPFC_MBOX_OPCODE_SEND_ACTIVATION 0x73 #define LPFC_MBOX_OPCODE_RESET_LICENSES 0x74 +#define LPFC_MBOX_OPCODE_REG_CONGESTION_BUF 0x8E #define LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO 0x9A #define LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT 0x9B #define LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT 0x9C @@ -1116,6 +1134,12 @@ struct lpfc_mbx_sge { uint32_t length; }; +struct lpfc_mbx_host_buf { + uint32_t length; + uint32_t pa_lo; + uint32_t pa_hi; +}; + struct lpfc_mbx_nembed_cmd { struct lpfc_sli4_cfg_mhdr cfg_mhdr; #define LPFC_SLI4_MBX_SGE_MAX_PAGES 19 @@ -1126,6 +1150,63 @@ struct lpfc_mbx_nembed_sge_virt { void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES]; }; +struct lpfc_mbx_read_object { /* Version 0 */ + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_rd_object_rlen_SHIFT 0 +#define lpfc_mbx_rd_object_rlen_MASK 0x00FFFFFF +#define lpfc_mbx_rd_object_rlen_WORD word0 + uint32_t rd_object_offset; + uint32_t rd_object_name[26]; + uint32_t rd_object_cnt; + struct lpfc_mbx_host_buf rd_object_hbuf[4]; + } request; + struct { + uint32_t rd_object_actual_rlen; + uint32_t word1; +#define lpfc_mbx_rd_object_eof_SHIFT 31 +#define lpfc_mbx_rd_object_eof_MASK 0x1 +#define lpfc_mbx_rd_object_eof_WORD word1 + } response; + } u; +}; + +struct lpfc_mbx_write_object { /* Version 0 */ + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_wr_object_rlen_SHIFT 0 +#define lpfc_mbx_wr_object_rlen_MASK 0x00FFFFFF +#define lpfc_mbx_wr_object_rlen_WORD word0 +#define lpfc_mbx_wr_object_noc_SHIFT 30 +#define lpfc_mbx_wr_object_noc_MASK 0x1 +#define lpfc_mbx_wr_object_noc_WORD word0 +#define lpfc_mbx_wr_object_eof_SHIFT 31 +#define lpfc_mbx_wr_object_eof_MASK 0x1 +#define lpfc_mbx_wr_object_eof_WORD word0 + uint32_t wr_object_offset; + uint32_t wr_object_name[26]; +#define LPFC_OBJ_NAME_SZ 104 /* 26 x sizeof(uint32_t) is 104. */ + uint32_t wr_object_cnt; + struct lpfc_mbx_host_buf wr_object_hbuf[4]; + } request; + struct { + uint32_t wr_object_actual_rlen; + uint32_t word1; +#define lpfc_mbx_wr_object_reset_SHIFT 0 +#define lpfc_mbx_wr_object_reset_MASK 0xff +#define lpfc_mbx_wr_object_reset_WORD word1 +#define LPFC_NO_RESET_REQ 0x0 +#define LPFC_PHYS_DEVICE_RESET_REQ 0x1 +#define LPFC_FW_RESET_REQ 0x2 +#define LPFC_PROTOCOL_RESET_REQ 0x3 + } response; + } u; +}; + struct lpfc_mbx_eq_create { struct mbox_header header; union { @@ -1434,7 +1515,7 @@ struct lpfc_mbx_wq_create { #define lpfc_mbx_wq_create_page_size_SHIFT 0 #define lpfc_mbx_wq_create_page_size_MASK 0x000000FF #define lpfc_mbx_wq_create_page_size_WORD word1 -#define LPFC_WQ_PAGE_SIZE_4096 0x1 +#define LPFC_WQ_PAGE_SIZE_4096 0x1 #define lpfc_mbx_wq_create_dpp_req_SHIFT 15 #define lpfc_mbx_wq_create_dpp_req_MASK 0x00000001 #define lpfc_mbx_wq_create_dpp_req_WORD word1 @@ -2321,6 +2402,8 @@ struct lpfc_mbx_redisc_fcf_tbl { #define ADD_STATUS_OPERATION_ALREADY_ACTIVE 0x67 #define ADD_STATUS_FW_NOT_SUPPORTED 0xEB #define ADD_STATUS_INVALID_REQUEST 0x4B +#define ADD_STATUS_INVALID_OBJECT_NAME 0xA0 +#define ADD_STATUS_FW_DOWNLOAD_HW_DISABLED 0x58 struct lpfc_mbx_sli4_config { struct mbox_header header; @@ -2792,6 +2875,15 @@ struct lpfc_mbx_read_rev { struct lpfc_mbx_read_config { uint32_t word1; +#define lpfc_mbx_rd_conf_acs_SHIFT 27 /* alarm signaling */ +#define lpfc_mbx_rd_conf_acs_MASK 0x00000001 +#define lpfc_mbx_rd_conf_acs_WORD word1 +#define lpfc_mbx_rd_conf_wcs_SHIFT 28 /* warning signaling */ +#define lpfc_mbx_rd_conf_wcs_MASK 0x00000001 +#define lpfc_mbx_rd_conf_wcs_WORD word1 +#define lpfc_mbx_rd_conf_fawwpn_inuse_SHIFT 30 +#define lpfc_mbx_rd_conf_fawwpn_inuse_MASK 0x00000001 +#define lpfc_mbx_rd_conf_fawwpn_inuse_WORD word1 #define lpfc_mbx_rd_conf_extnts_inuse_SHIFT 31 #define lpfc_mbx_rd_conf_extnts_inuse_MASK 0x00000001 #define lpfc_mbx_rd_conf_extnts_inuse_WORD word1 @@ -2810,6 +2902,15 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_trunk_SHIFT 12 #define lpfc_mbx_rd_conf_trunk_MASK 0x0000000F #define lpfc_mbx_rd_conf_trunk_WORD word2 +#define lpfc_mbx_rd_conf_pt_SHIFT 20 +#define lpfc_mbx_rd_conf_pt_MASK 0x00000003 +#define lpfc_mbx_rd_conf_pt_WORD word2 +#define lpfc_mbx_rd_conf_tf_SHIFT 22 +#define lpfc_mbx_rd_conf_tf_MASK 0x00000001 +#define lpfc_mbx_rd_conf_tf_WORD word2 +#define lpfc_mbx_rd_conf_ptv_SHIFT 23 +#define lpfc_mbx_rd_conf_ptv_MASK 0x00000001 +#define lpfc_mbx_rd_conf_ptv_WORD word2 #define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_WORD word2 @@ -2963,6 +3064,62 @@ struct lpfc_mbx_request_features { #define lpfc_mbx_rq_ftr_rsp_mrqp_WORD word3 }; +struct lpfc_mbx_supp_pages { + uint32_t word1; +#define qs_SHIFT 0 +#define qs_MASK 0x00000001 +#define qs_WORD word1 +#define wr_SHIFT 1 +#define wr_MASK 0x00000001 +#define wr_WORD word1 +#define pf_SHIFT 8 +#define pf_MASK 0x000000ff +#define pf_WORD word1 +#define cpn_SHIFT 16 +#define cpn_MASK 0x000000ff +#define cpn_WORD word1 + uint32_t word2; +#define list_offset_SHIFT 0 +#define list_offset_MASK 0x000000ff +#define list_offset_WORD word2 +#define next_offset_SHIFT 8 +#define next_offset_MASK 0x000000ff +#define next_offset_WORD word2 +#define elem_cnt_SHIFT 16 +#define elem_cnt_MASK 0x000000ff +#define elem_cnt_WORD word2 + uint32_t word3; +#define pn_0_SHIFT 24 +#define pn_0_MASK 0x000000ff +#define pn_0_WORD word3 +#define pn_1_SHIFT 16 +#define pn_1_MASK 0x000000ff +#define pn_1_WORD word3 +#define pn_2_SHIFT 8 +#define pn_2_MASK 0x000000ff +#define pn_2_WORD word3 +#define pn_3_SHIFT 0 +#define pn_3_MASK 0x000000ff +#define pn_3_WORD word3 + uint32_t word4; +#define pn_4_SHIFT 24 +#define pn_4_MASK 0x000000ff +#define pn_4_WORD word4 +#define pn_5_SHIFT 16 +#define pn_5_MASK 0x000000ff +#define pn_5_WORD word4 +#define pn_6_SHIFT 8 +#define pn_6_MASK 0x000000ff +#define pn_6_WORD word4 +#define pn_7_SHIFT 0 +#define pn_7_MASK 0x000000ff +#define pn_7_WORD word4 + uint32_t rsvd[27]; +#define LPFC_SUPP_PAGES 0 +#define LPFC_BLOCK_GUARD_PROFILES 1 +#define LPFC_SLI4_PARAMETERS 2 +}; + struct lpfc_mbx_memory_dump_type3 { uint32_t word1; #define lpfc_mbx_memory_dump_type3_type_SHIFT 0 @@ -3179,6 +3336,121 @@ struct user_eeprom { uint8_t reserved191[57]; }; +struct lpfc_mbx_pc_sli4_params { + uint32_t word1; +#define qs_SHIFT 0 +#define qs_MASK 0x00000001 +#define qs_WORD word1 +#define wr_SHIFT 1 +#define wr_MASK 0x00000001 +#define wr_WORD word1 +#define pf_SHIFT 8 +#define pf_MASK 0x000000ff +#define pf_WORD word1 +#define cpn_SHIFT 16 +#define cpn_MASK 0x000000ff +#define cpn_WORD word1 + uint32_t word2; +#define if_type_SHIFT 0 +#define if_type_MASK 0x00000007 +#define if_type_WORD word2 +#define sli_rev_SHIFT 4 +#define sli_rev_MASK 0x0000000f +#define sli_rev_WORD word2 +#define sli_family_SHIFT 8 +#define sli_family_MASK 0x000000ff +#define sli_family_WORD word2 +#define featurelevel_1_SHIFT 16 +#define featurelevel_1_MASK 0x000000ff +#define featurelevel_1_WORD word2 +#define featurelevel_2_SHIFT 24 +#define featurelevel_2_MASK 0x0000001f +#define featurelevel_2_WORD word2 + uint32_t word3; +#define fcoe_SHIFT 0 +#define fcoe_MASK 0x00000001 +#define fcoe_WORD word3 +#define fc_SHIFT 1 +#define fc_MASK 0x00000001 +#define fc_WORD word3 +#define nic_SHIFT 2 +#define nic_MASK 0x00000001 +#define nic_WORD word3 +#define iscsi_SHIFT 3 +#define iscsi_MASK 0x00000001 +#define iscsi_WORD word3 +#define rdma_SHIFT 4 +#define rdma_MASK 0x00000001 +#define rdma_WORD word3 + uint32_t sge_supp_len; +#define SLI4_PAGE_SIZE 4096 + uint32_t word5; +#define if_page_sz_SHIFT 0 +#define if_page_sz_MASK 0x0000ffff +#define if_page_sz_WORD word5 +#define loopbk_scope_SHIFT 24 +#define loopbk_scope_MASK 0x0000000f +#define loopbk_scope_WORD word5 +#define rq_db_window_SHIFT 28 +#define rq_db_window_MASK 0x0000000f +#define rq_db_window_WORD word5 + uint32_t word6; +#define eq_pages_SHIFT 0 +#define eq_pages_MASK 0x0000000f +#define eq_pages_WORD word6 +#define eqe_size_SHIFT 8 +#define eqe_size_MASK 0x000000ff +#define eqe_size_WORD word6 + uint32_t word7; +#define cq_pages_SHIFT 0 +#define cq_pages_MASK 0x0000000f +#define cq_pages_WORD word7 +#define cqe_size_SHIFT 8 +#define cqe_size_MASK 0x000000ff +#define cqe_size_WORD word7 + uint32_t word8; +#define mq_pages_SHIFT 0 +#define mq_pages_MASK 0x0000000f +#define mq_pages_WORD word8 +#define mqe_size_SHIFT 8 +#define mqe_size_MASK 0x000000ff +#define mqe_size_WORD word8 +#define mq_elem_cnt_SHIFT 16 +#define mq_elem_cnt_MASK 0x000000ff +#define mq_elem_cnt_WORD word8 + uint32_t word9; +#define wq_pages_SHIFT 0 +#define wq_pages_MASK 0x0000ffff +#define wq_pages_WORD word9 +#define wqe_size_SHIFT 8 +#define wqe_size_MASK 0x000000ff +#define wqe_size_WORD word9 + uint32_t word10; +#define rq_pages_SHIFT 0 +#define rq_pages_MASK 0x0000ffff +#define rq_pages_WORD word10 +#define rqe_size_SHIFT 8 +#define rqe_size_MASK 0x000000ff +#define rqe_size_WORD word10 + uint32_t word11; +#define hdr_pages_SHIFT 0 +#define hdr_pages_MASK 0x0000000f +#define hdr_pages_WORD word11 +#define hdr_size_SHIFT 8 +#define hdr_size_MASK 0x0000000f +#define hdr_size_WORD word11 +#define hdr_pp_align_SHIFT 16 +#define hdr_pp_align_MASK 0x0000ffff +#define hdr_pp_align_WORD word11 + uint32_t word12; +#define sgl_pages_SHIFT 0 +#define sgl_pages_MASK 0x0000000f +#define sgl_pages_WORD word12 +#define sgl_pp_align_SHIFT 16 +#define sgl_pp_align_MASK 0x0000ffff +#define sgl_pp_align_WORD word12 + uint32_t rsvd_13_63[51]; +}; #define SLI4_PAGE_ALIGN(addr) (((addr)+((SLI4_PAGE_SIZE)-1)) \ &(~((SLI4_PAGE_SIZE)-1))) @@ -3305,7 +3577,6 @@ struct lpfc_sli4_parameters { #define cfg_nosr_SHIFT 9 #define cfg_nosr_MASK 0x00000001 #define cfg_nosr_WORD word19 - #define cfg_bv1s_SHIFT 10 #define cfg_bv1s_MASK 0x00000001 #define cfg_bv1s_WORD word19 @@ -3313,14 +3584,28 @@ struct lpfc_sli4_parameters { #define cfg_nsler_SHIFT 12 #define cfg_nsler_MASK 0x00000001 #define cfg_nsler_WORD word19 +#define cfg_pvl_SHIFT 13 +#define cfg_pvl_MASK 0x00000001 +#define cfg_pvl_WORD word19 + +#define cfg_pbde_SHIFT 20 +#define cfg_pbde_MASK 0x00000001 +#define cfg_pbde_WORD word19 uint32_t word20; #define cfg_max_tow_xri_SHIFT 0 #define cfg_max_tow_xri_MASK 0x0000ffff #define cfg_max_tow_xri_WORD word20 - uint32_t word21; /* RESERVED */ - uint32_t word22; /* RESERVED */ + uint32_t word21; +#define cfg_e2em_attr_value_SHIFT 0 +#define cfg_e2em_attr_value_MASK 0x0000ffff +#define cfg_e2em_attr_value_WORD word21 +#define cfg_cmf_SHIFT 24 +#define cfg_cmf_MASK 0x000000ff +#define cfg_cmf_WORD word21 + + uint32_t cgn_buf_size; /* word 22 */ uint32_t word23; /* RESERVED */ uint32_t word24; @@ -3347,21 +3632,46 @@ struct lpfc_sli4_parameters { }; #define LPFC_SET_UE_RECOVERY 0x10 -#define LPFC_SET_MDS_DIAGS 0x11 +#define LPFC_SET_MDS_DIAGS 0x12 +#define LPFC_SET_CGN_SIGNAL 0x1f +#define LPFC_SET_DUAL_DUMP 0x1e +#define LPFC_SET_ENABLE_E2E 0x21 +#define LPFC_SET_ENABLE_CMF 0x24 struct lpfc_mbx_set_feature { struct mbox_header header; - uint32_t feature; - uint32_t param_len; - uint32_t word6; + u32 feature; + u32 param_len; + u32 word6; #define lpfc_mbx_set_feature_UER_SHIFT 0 #define lpfc_mbx_set_feature_UER_MASK 0x00000001 #define lpfc_mbx_set_feature_UER_WORD word6 -#define lpfc_mbx_set_feature_mds_SHIFT 0 +#define lpfc_mbx_set_feature_mds_SHIFT 2 #define lpfc_mbx_set_feature_mds_MASK 0x00000001 #define lpfc_mbx_set_feature_mds_WORD word6 #define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT 1 #define lpfc_mbx_set_feature_mds_deep_loopbk_MASK 0x00000001 #define lpfc_mbx_set_feature_mds_deep_loopbk_WORD word6 +#define lpfc_mbx_set_feature_CGN_warn_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_warn_freq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_CGN_warn_freq_WORD word6 +#define lpfc_mbx_set_feature_dd_SHIFT 0 +#define lpfc_mbx_set_feature_dd_MASK 0x00000001 +#define lpfc_mbx_set_feature_dd_WORD word6 +#define lpfc_mbx_set_feature_ddquery_SHIFT 1 +#define lpfc_mbx_set_feature_ddquery_MASK 0x00000001 +#define lpfc_mbx_set_feature_ddquery_WORD word6 +#define LPFC_DISABLE_DUAL_DUMP 0 +#define LPFC_ENABLE_DUAL_DUMP 1 +#define LPFC_QUERY_OP_DUAL_DUMP 2 +#define lpfc_mbx_set_feature_cmf_SHIFT 0 +#define lpfc_mbx_set_feature_cmf_MASK 0x00000001 +#define lpfc_mbx_set_feature_cmf_WORD word6 +#define lpfc_mbx_set_feature_e2e_SHIFT 0 +#define lpfc_mbx_set_feature_e2e_MASK 0x0000ffff +#define lpfc_mbx_set_feature_e2e_WORD word6 +#define lpfc_mbx_set_feature_e2elunq_SHIFT 16 +#define lpfc_mbx_set_feature_e2elunq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_e2elunq_WORD word6 uint32_t word7; #define lpfc_mbx_set_feature_UERP_SHIFT 0 #define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff @@ -3369,16 +3679,51 @@ struct lpfc_mbx_set_feature { #define lpfc_mbx_set_feature_UESR_SHIFT 16 #define lpfc_mbx_set_feature_UESR_MASK 0x0000ffff #define lpfc_mbx_set_feature_UESR_WORD word7 +#define lpfc_mbx_set_feature_CGN_alarm_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_alarm_freq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_CGN_alarm_freq_WORD word7 + u32 word8; +#define lpfc_mbx_set_feature_CGN_acqe_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_acqe_freq_MASK 0x000000ff +#define lpfc_mbx_set_feature_CGN_acqe_freq_WORD word8 }; #define LPFC_SET_HOST_OS_DRIVER_VERSION 0x2 +#define LPFC_SET_HOST_DATE_TIME 0x4 + +struct lpfc_mbx_set_host_date_time { + uint32_t word6; +#define lpfc_mbx_set_host_month_WORD word6 +#define lpfc_mbx_set_host_month_SHIFT 16 +#define lpfc_mbx_set_host_month_MASK 0xFF +#define lpfc_mbx_set_host_day_WORD word6 +#define lpfc_mbx_set_host_day_SHIFT 8 +#define lpfc_mbx_set_host_day_MASK 0xFF +#define lpfc_mbx_set_host_year_WORD word6 +#define lpfc_mbx_set_host_year_SHIFT 0 +#define lpfc_mbx_set_host_year_MASK 0xFF + uint32_t word7; +#define lpfc_mbx_set_host_hour_WORD word7 +#define lpfc_mbx_set_host_hour_SHIFT 16 +#define lpfc_mbx_set_host_hour_MASK 0xFF +#define lpfc_mbx_set_host_min_WORD word7 +#define lpfc_mbx_set_host_min_SHIFT 8 +#define lpfc_mbx_set_host_min_MASK 0xFF +#define lpfc_mbx_set_host_sec_WORD word7 +#define lpfc_mbx_set_host_sec_SHIFT 0 +#define lpfc_mbx_set_host_sec_MASK 0xFF +}; + struct lpfc_mbx_set_host_data { #define LPFC_HOST_OS_DRIVER_VERSION_SIZE 48 struct mbox_header header; uint32_t param_id; uint32_t param_len; - uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE]; + union { + uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE]; + struct lpfc_mbx_set_host_date_time tm; + } un; }; struct lpfc_mbx_set_trunk_mode { @@ -3396,6 +3741,21 @@ struct lpfc_mbx_get_sli4_parameters { struct lpfc_sli4_parameters sli4_parameters; }; +struct lpfc_mbx_reg_congestion_buf { + struct mbox_header header; + uint32_t word0; +#define lpfc_mbx_reg_cgn_buf_type_WORD word0 +#define lpfc_mbx_reg_cgn_buf_type_SHIFT 0 +#define lpfc_mbx_reg_cgn_buf_type_MASK 0xFF +#define lpfc_mbx_reg_cgn_buf_cnt_WORD word0 +#define lpfc_mbx_reg_cgn_buf_cnt_SHIFT 16 +#define lpfc_mbx_reg_cgn_buf_cnt_MASK 0xFF + uint32_t word1; + uint32_t length; + uint32_t addr_lo; + uint32_t addr_hi; +}; + struct lpfc_rscr_desc_generic { #define LPFC_RSRC_DESC_WSIZE 22 uint32_t desc[LPFC_RSRC_DESC_WSIZE]; @@ -3561,6 +3921,9 @@ struct lpfc_controller_attribute { #define lpfc_cntl_attr_eprom_ver_hi_SHIFT 8 #define lpfc_cntl_attr_eprom_ver_hi_MASK 0x000000ff #define lpfc_cntl_attr_eprom_ver_hi_WORD word17 +#define lpfc_cntl_attr_flash_id_SHIFT 16 +#define lpfc_cntl_attr_flash_id_MASK 0x000000ff +#define lpfc_cntl_attr_flash_id_WORD word17 uint32_t mbx_da_struct_ver; uint32_t ep_fw_da_struct_ver; uint32_t ncsi_ver_str[3]; @@ -3702,6 +4065,90 @@ struct lpfc_mbx_get_port_name { #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 #define MB_CQE_STATUS_DMA_FAILED 0x5 +#define LPFC_MBX_OBJECT_NAME_LEN_DW 26 +#define LPFC_MBX_AUTH_RD_CONFIG_MAX_BDE 8 +struct lpfc_mbx_auth_rd_object { + union lpfc_sli4_cfg_shdr cfg_shdr; + union { + struct { + uint32_t word4; +#define lpfc_rd_object_read_length_SHIFT 0 +#define lpfc_rd_object_read_length_MASK 0x00FFFFFF +#define lpfc_rd_object_read_length_WORD word4 + uint32_t read_offset; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; + uint32_t bde_count; + struct ulp_bde64 bde[LPFC_MBX_AUTH_RD_CONFIG_MAX_BDE]; + } request; + struct { + uint32_t actual_read_length; + uint32_t word5; +#define lpfc_rd_object_eof_SHIFT 31 +#define lpfc_rd_object_eof_MASK 0x00000001 +#define lpfc_rd_object_eof_WORD word5 + } response; + } u; +}; + +#define LPFC_MBX_RD_CONFIG_MAX_BDE 1 +struct lpfc_mbx_rd_object { + struct mbox_header header; + union { + struct { + uint32_t word4; +#define lpfc_rd_object_read_length_SHIFT 0 +#define lpfc_rd_object_read_length_MASK 0x00FFFFFF +#define lpfc_rd_object_read_length_WORD word4 + uint32_t read_offset; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; + uint32_t bde_count; + struct ulp_bde64 bde[LPFC_MBX_RD_CONFIG_MAX_BDE]; + } request; + struct { + uint32_t actual_read_length; + uint32_t word5; +#define lpfc_rd_object_eof_SHIFT 31 +#define lpfc_rd_object_eof_MASK 0x00000001 +#define lpfc_rd_object_eof_WORD word5 + } response; + } u; +}; + +#define LPFC_MBX_AUTH_WR_CONFIG_MAX_BDE 8 +struct lpfc_mbx_auth_wr_object { + union lpfc_sli4_cfg_shdr cfg_shdr; + union { + struct { + uint32_t word4; +#define lpfc_wr_object_eof_SHIFT 31 +#define lpfc_wr_object_eof_MASK 0x00000001 +#define lpfc_wr_object_eof_WORD word4 +#define lpfc_wr_object_eas_SHIFT 29 +#define lpfc_wr_object_eas_MASK 0x00000001 +#define lpfc_wr_object_eas_WORD word4 +#define lpfc_wr_object_write_length_SHIFT 0 +#define lpfc_wr_object_write_length_MASK 0x00FFFFFF +#define lpfc_wr_object_write_length_WORD word4 + uint32_t write_offset; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; + uint32_t bde_count; + struct ulp_bde64 bde[LPFC_MBX_AUTH_WR_CONFIG_MAX_BDE]; + } request; + struct { + uint32_t actual_write_length; + uint32_t word5; +#define lpfc_wr_object_change_status_SHIFT 0 +#define lpfc_wr_object_change_status_MASK 0x000000FF +#define lpfc_wr_object_change_status_WORD word5 +#define LPFC_CHANGE_STATUS_NO_RESET_NEEDED 0x00 +#define LPFC_CHANGE_STATUS_PHYS_DEV_RESET 0x01 +#define LPFC_CHANGE_STATUS_FW_RESET 0x02 +#define LPFC_CHANGE_STATUS_PORT_MIGRATION 0x04 +#define LPFC_CHANGE_STATUS_PCI_RESET 0x05 + } response; + } u; +}; + #define LPFC_MBX_WR_CONFIG_MAX_BDE 1 struct lpfc_mbx_wr_object { struct mbox_header header; @@ -3718,7 +4165,7 @@ struct lpfc_mbx_wr_object { #define lpfc_wr_object_write_length_MASK 0x00FFFFFF #define lpfc_wr_object_write_length_WORD word4 uint32_t write_offset; - uint32_t object_name[26]; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; uint32_t bde_count; struct ulp_bde64 bde[LPFC_MBX_WR_CONFIG_MAX_BDE]; } request; @@ -3733,10 +4180,22 @@ struct lpfc_mbx_wr_object { #define LPFC_CHANGE_STATUS_FW_RESET 0x02 #define LPFC_CHANGE_STATUS_PORT_MIGRATION 0x04 #define LPFC_CHANGE_STATUS_PCI_RESET 0x05 +#define lpfc_wr_object_csf_SHIFT 8 +#define lpfc_wr_object_csf_MASK 0x00000001 +#define lpfc_wr_object_csf_WORD word5 } response; } u; }; +struct lpfc_mbx_del_object { + struct mbox_header header; + struct { + uint32_t word4; + uint32_t word5; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; + } request; +}; + /* mailbox queue entry structure */ struct lpfc_mqe { uint32_t word0; @@ -3764,6 +4223,8 @@ struct lpfc_mqe { struct lpfc_mbx_unreg_fcfi unreg_fcfi; struct lpfc_mbx_mq_create mq_create; struct lpfc_mbx_mq_create_ext mq_create_ext; + struct lpfc_mbx_read_object read_object; + struct lpfc_mbx_write_object write_object; struct lpfc_mbx_eq_create eq_create; struct lpfc_mbx_modify_eq_delay eq_delay; struct lpfc_mbx_cq_create cq_create; @@ -3788,13 +4249,18 @@ struct lpfc_mqe { struct lpfc_mbx_post_hdr_tmpl hdr_tmpl; struct lpfc_mbx_query_fw_config query_fw_cfg; struct lpfc_mbx_set_beacon_config beacon_config; + struct lpfc_mbx_supp_pages supp_pages; + struct lpfc_mbx_pc_sli4_params sli4_params; struct lpfc_mbx_get_sli4_parameters get_sli4_parameters; + struct lpfc_mbx_reg_congestion_buf reg_congestion_buf; struct lpfc_mbx_set_link_diag_state link_diag_state; struct lpfc_mbx_set_link_diag_loopback link_diag_loopback; struct lpfc_mbx_run_link_diag_test link_diag_test; struct lpfc_mbx_get_func_cfg get_func_cfg; struct lpfc_mbx_get_prof_cfg get_prof_cfg; + struct lpfc_mbx_rd_object rd_object; struct lpfc_mbx_wr_object wr_object; + struct lpfc_mbx_del_object del_object; struct lpfc_mbx_get_port_name get_port_name; struct lpfc_mbx_set_feature set_feature; struct lpfc_mbx_memory_dump_type3 mem_dump_type3; @@ -3837,12 +4303,13 @@ struct lpfc_mcqe { #define lpfc_trailer_code_SHIFT 8 #define lpfc_trailer_code_MASK 0x000000FF #define lpfc_trailer_code_WORD trailer -#define LPFC_TRAILER_CODE_LINK 0x1 -#define LPFC_TRAILER_CODE_FCOE 0x2 -#define LPFC_TRAILER_CODE_DCBX 0x3 -#define LPFC_TRAILER_CODE_GRP5 0x5 -#define LPFC_TRAILER_CODE_FC 0x10 -#define LPFC_TRAILER_CODE_SLI 0x11 +#define LPFC_TRAILER_CODE_LINK 0x1 +#define LPFC_TRAILER_CODE_FCOE 0x2 +#define LPFC_TRAILER_CODE_DCBX 0x3 +#define LPFC_TRAILER_CODE_GRP5 0x5 +#define LPFC_TRAILER_CODE_FC 0x10 +#define LPFC_TRAILER_CODE_SLI 0x11 +#define LPFC_TRAILER_CODE_CMSTAT 0x13 }; struct lpfc_acqe_link { @@ -4077,11 +4544,25 @@ struct lpfc_acqe_misconfigured_event { #define LPFC_SLI_EVENT_STATUS_UNCERTIFIED 0x05 }; +struct lpfc_acqe_cgn_signal { + u32 word0; +#define lpfc_warn_acqe_SHIFT 0 +#define lpfc_warn_acqe_MASK 0x7FFFFFFF +#define lpfc_warn_acqe_WORD word0 +#define lpfc_imm_acqe_SHIFT 31 +#define lpfc_imm_acqe_MASK 0x1 +#define lpfc_imm_acqe_WORD word0 + u32 alarm_cnt; + u32 word2; + u32 trailer; +}; + struct lpfc_acqe_sli { - uint32_t event_data1; - uint32_t event_data2; - uint32_t reserved; - uint32_t trailer; + u32 event_data1; +#define LPFC_SLI_CONG_PARAM_CHANGE_EVENT 0x2 + u32 event_data2; + u32 reserved; + u32 trailer; #define LPFC_SLI_EVENT_TYPE_PORT_ERROR 0x1 #define LPFC_SLI_EVENT_TYPE_OVER_TEMP 0x2 #define LPFC_SLI_EVENT_TYPE_NORM_TEMP 0x3 @@ -4089,6 +4570,11 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED 0x9 #define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT 0xA +#define LPFC_SLI_EVENT_TYPE_PORT_INT_EVT 0xD +#define LPFC_SLI_EVENT_TYPE_PORT_PARAMS_CHG 0xE +#define LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN 0xF +#define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE 0x10 +#define LPFC_SLI_EVENT_TYPE_CGN_SIGNAL 0x11 }; /* @@ -4249,6 +4735,9 @@ struct wqe_common { #define wqe_sup_SHIFT 6 #define wqe_sup_MASK 0x00000001 #define wqe_sup_WORD word11 +#define wqe_ffrq_SHIFT 6 +#define wqe_ffrq_MASK 0x00000001 +#define wqe_ffrq_WORD word11 #define wqe_wqec_SHIFT 7 #define wqe_wqec_MASK 0x00000001 #define wqe_wqec_WORD word11 @@ -4487,9 +4976,73 @@ struct create_xri_wqe { uint32_t rsvd_12_15[4]; /* word 12-15 */ }; +#define INHIBIT_ABORT 1 #define T_REQUEST_TAG 3 #define T_XRI_TAG 1 +struct cmf_sync_wqe { // CMF_DBG - this may change + uint32_t rsrvd[3]; + uint32_t word3; +#define cmf_sync_interval_SHIFT 0 +#define cmf_sync_interval_MASK 0x00000ffff +#define cmf_sync_interval_WORD word3 +#define cmf_sync_afpin_SHIFT 16 +#define cmf_sync_afpin_MASK 0x000000001 +#define cmf_sync_afpin_WORD word3 +#define cmf_sync_asig_SHIFT 17 +#define cmf_sync_asig_MASK 0x000000001 +#define cmf_sync_asig_WORD word3 +#define cmf_sync_op_SHIFT 20 +#define cmf_sync_op_MASK 0x00000000f +#define cmf_sync_op_WORD word3 +#define cmf_sync_ver_SHIFT 24 +#define cmf_sync_ver_MASK 0x0000000ff +#define cmf_sync_ver_WORD word3 +#define LPFC_CMF_SYNC_VER 1 + uint32_t event_tag; + uint32_t word5; +#define cmf_sync_wsigmax_SHIFT 0 +#define cmf_sync_wsigmax_MASK 0x00000ffff +#define cmf_sync_wsigmax_WORD word5 +#define cmf_sync_wsigcnt_SHIFT 16 +#define cmf_sync_wsigcnt_MASK 0x00000ffff +#define cmf_sync_wsigcnt_WORD word5 + uint32_t word6; + uint32_t word7; +#define cmf_sync_cmnd_SHIFT 8 +#define cmf_sync_cmnd_MASK 0x0000000ff +#define cmf_sync_cmnd_WORD word7 + uint32_t word8; + uint32_t word9; +#define cmf_sync_reqtag_SHIFT 0 +#define cmf_sync_reqtag_MASK 0x00000ffff +#define cmf_sync_reqtag_WORD word9 +#define cmf_sync_wfpinmax_SHIFT 16 +#define cmf_sync_wfpinmax_MASK 0x0000000ff +#define cmf_sync_wfpinmax_WORD word9 +#define cmf_sync_wfpincnt_SHIFT 24 +#define cmf_sync_wfpincnt_MASK 0x0000000ff +#define cmf_sync_wfpincnt_WORD word9 + uint32_t word10; +#define cmf_sync_qosd_SHIFT 9 +#define cmf_sync_qosd_MASK 0x00000001 +#define cmf_sync_qosd_WORD word10 + uint32_t word11; +#define cmf_sync_cmd_type_SHIFT 0 +#define cmf_sync_cmd_type_MASK 0x0000000f +#define cmf_sync_cmd_type_WORD word11 +#define cmf_sync_wqec_SHIFT 7 +#define cmf_sync_wqec_MASK 0x00000001 +#define cmf_sync_wqec_WORD word11 +#define cmf_sync_cqid_SHIFT 16 +#define cmf_sync_cqid_MASK 0x0000ffff +#define cmf_sync_cqid_WORD word11 + uint32_t read_bytes; + uint32_t word13; + uint32_t word14; + uint32_t word15; +}; + struct abort_cmd_wqe { uint32_t rsrvd[3]; uint32_t word3; @@ -4552,6 +5105,19 @@ struct fcp_icmnd64_wqe { uint32_t rsvd_12_15[4]; /* word 12-15 */ }; +#define CMD_SEND_FRAME 0xE1 + +struct send_frame_wqe { + struct ulp_bde64 bde; /* words 0-2 */ + uint32_t frame_len; /* word 3 */ + uint32_t fc_hdr_wd0; /* word 4 */ + uint32_t fc_hdr_wd1; /* word 5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t fc_hdr_wd2; /* word 12 */ + uint32_t fc_hdr_wd3; /* word 13 */ + uint32_t fc_hdr_wd4; /* word 14 */ + uint32_t fc_hdr_wd5; /* word 15 */ +}; struct fcp_trsp64_wqe { struct ulp_bde64 bde; uint32_t response_len; @@ -4581,20 +5147,270 @@ struct fcp_treceive64_wqe { }; #define TXRDY_PAYLOAD_LEN 12 -#define CMD_SEND_FRAME 0xE1 -struct send_frame_wqe { - struct ulp_bde64 bde; /* words 0-2 */ - uint32_t frame_len; /* word 3 */ - uint32_t fc_hdr_wd0; /* word 4 */ - uint32_t fc_hdr_wd1; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t fc_hdr_wd2; /* word 12 */ - uint32_t fc_hdr_wd3; /* word 13 */ - uint32_t fc_hdr_wd4; /* word 14 */ - uint32_t fc_hdr_wd5; /* word 15 */ +/* EDC Exchange Diagnostic Capabilities Structure layout. + * Link Faults (T11 standard, but not supported.) + * Congestion Detection (future, but supported now) + */ +struct cgn_det_desc { +#define CGN_DET_CAP_DESC_TAG 0x0001000f + u32 cgn_det_tag; + u32 cgn_desc_len; + u32 word2; /* transmit signal capability */ +#define xmt_sig_cap_SHIFT 0 +#define xmt_sig_cap_MASK 0x0000000f +#define xmt_sig_cap_WORD word2 +#define XMT_SIG_CAP_NO_SPT 0 +#define XMT_SIG_CAP_WARN_SPT 1 +#define XMT_SIG_CAP_BOTH_SPT 2 + u32 word3; /* transmit signal frequency */ +#define xmt_sig_freq_cyc_SHIFT 16 +#define xmt_sig_freq_cyc_MASK 0x000003ff +#define xmt_sig_freq_cyc_WORD word3 +#define XMT_SIG_FREQ_CYC_NO_SPT 0 +#define XMT_SIG_FREQ_CYC_MIN 1 +#define XMT_SIG_FREQ_CYC_MAX 999 +#define xmt_sig_freq_scale_SHIFT 0 +#define xmt_sig_freq_scale_MASK 0x0000000f +#define xmt_sig_freq_scale_WORD word3 +#define XMT_SIG_FREQ_SCALE_NO_SPT 0 +#define XMT_SIG_FREQ_SCALE_SEC 1 +#define XMT_SIG_FREQ_SCALE_MSEC 2 +#define XMT_SIG_FREQ_SCALE_USEC 3 +#define XMT_SIG_FREQ_SCALE_NSEC 4 + u32 word4; /* receive signal capability */ +#define rcv_sig_cap_SHIFT 0 +#define rcv_sig_cap_MASK 0x0000000f +#define rcv_sig_cap_WORD word4 +#define RCV_SIG_CAP_NO_SPT 0 +#define RCV_SIG_CAP_WARN_SPT 1 +#define RCV_SIG_CAP_BOTH_SPT 2 + u32 word5; /* receive signal frequency */ +#define rcv_sig_freq_cyc_SHIFT 16 +#define rcv_sig_freq_cyc_MASK 0x000003ff +#define rcv_sig_freq_cyc_WORD word5 +#define RCV_SIG_FREQ_CYC_NO_SPT 0 +#define RCV_SIG_FREQ_CYC_MIN 1 +#define RCV_SIG_FREQ_CYC_DFT 100 +#define RCV_SIG_FREQ_CYC_MAX 999 +#define rcv_sig_freq_scale_SHIFT 0 +#define rcv_sig_freq_scale_MASK 0x0000000f +#define rcv_sig_freq_scale_WORD word5 +#define RCV_SIG_FREQ_SCALE_NO_SPT 0 +#define RCV_SIG_FREQ_SCALE_SEC 1 +#define RCV_SIG_FREQ_SCALE_MSEC 2 +#define RCV_SIG_FREQ_SCALE_USEC 3 +#define RCV_SIG_FREQ_SCALE_NSEC 4 }; +/* This is the T11 definition targeting FC-FS-5 */ +struct link_flt_desc { +#define LINK_FLT_CAP_DESC_TAG 0x0001000d + u32 link_flt_cap_tag; + u32 desc_len; + u32 degrade_act_thld; + u32 degrade_deact_thld; + u32 fec_degrade_intvl; +}; + +/* Not a Link Fault or Congestion descriptor */ +struct unknown_desc { + u32 unk_tag; + u32 desc_len; +}; + +/* EDC supports two descriptors. When allocated, it is the + * size of this structure plus each supported descriptor. + */ +struct lpfc_els_edc_req { + u32 word0; +#define edc_els_req_SHIFT 24 +#define edc_els_req_MASK 0x000000ff +#define edc_els_req_WORD word0 + u32 desc_list_len; +}; + +/* Minimum structure defines for the EDC response. + * Balance is in buffer. + */ +struct lpfc_els_edc_rsp { + u32 word0; +#define edc_rsp_SHIFT 24 +#define edc_rsp_MASK 0x0000000ff +#define edc_rsp_WORD word0 + u32 desc_list_len; + u32 lnk_srv_req_word2; + u32 lnk_srv_req_word3; + u32 lnk_srv_req_word4; +}; + +enum lpfc_fpin_types { + LPFC_FPIN_LINK_INTEG, + LPFC_FPIN_DELIVERY, + LPFC_FPIN_PEER_CGN, + LPFC_FPIN_CGN, + LPFC_MAX_NUM_OF_FPIN_TYPES, +}; + +/* RDF - Register Diagnostic Functions Structure layout. + * The response structure is larger than the request forcing + * different structure defines to keep the command correct + * on the wire. + */ +struct rdf_desc { + uint32_t rdf_desc_tag; +#define ELS_FPIN_REG 0x00030001 + uint32_t rdf_desc_len; + uint32_t count; + uint32_t desc[LPFC_MAX_NUM_OF_FPIN_TYPES]; +}; + +struct lpfc_els_rdf_req { + uint32_t word0; +#define rdf_els_req_SHIFT 24 +#define rdf_els_req_MASK 0x000000ff +#define rdf_els_req_WORD word0 + uint32_t desc_list_len; + struct rdf_desc rdf_desc; +}; + +struct lpfc_els_rdf_rsp { + uint32_t word0; +#define edc_rsp_SHIFT 24 +#define edc_rsp_MASK 0x0000000ff +#define edc_rsp_WORD word0 + uint32_t desc_list_len; + uint32_t lnk_srv_req_word2; + uint32_t lnk_srv_req_word3; + uint32_t lnk_srv_req_word4; + struct rdf_desc rdf_desc; +}; + +/* FPIN Fabric Performance Impact Notification. + * + * FPIN layout: + * fpin_els_notify - two words + * FPIN event descriptor - N words describing the event data payload. + * The descriptor notify_tag tells the driver what descriptor + * is getting delivered. + * + * A note on the portlist payload. Only Link Integrity and Congestion + * Notifications have a portlist in the payload. The payload buffer is + * an MBUF with size 1KB. Payload takes maximally 12 words (Link Integrity) + * or 48 bytes. That leaves (1024 - 48) / 8 = 122 WWPNs in the portlist. + * The Congestion notification would have 123 WWPNs. It isn't clear + * the driver needs or wants to handle the portlist payload and the FW will + * only DMA the MBUF size provided. Given this, the implemenation + * isn't concerned about missing WWPNs. + * + */ +struct fpin_els_notify { + uint32_t word0; +#define fpin_els_req_SHIFT 24 +#define fpin_els_req_MASK 0x000000ff +#define fpin_els_req_WORD word0 + uint32_t fpin_list_len; +}; + +/* The Fabric broadcasts an FPIN Link Integrity Notification to all peer N_Port + * IDs that have registered for FPIN ELS notifications and are within the same + * zone as the impacted N_Port ID. + */ +struct fpin_link_integ_not { + uint32_t ntfy_tag; +#define FPIN_NOTIFY_LINK_INTEG 0x00020001 + uint32_t ntfy_desc_len; + uint32_t det_pname[2]; + uint32_t att_pname[2]; + uint32_t word6; +#define fpin_link_evt_type_SHIFT 16 +#define fpin_link_evt_type_MASK 0x0000ffff +#define fpin_link_evt_type_WORD word6 +#define fpin_link_evt_mod_SHIFT 0 +#define fpin_link_evt_mod_MASK 0x0000ffff +#define fpin_link_evt_mod_WORD word6 +#define FPIN_LINK_EVT_UNKNOWN 0x0 +#define FPIN_LINK_EVT_LINK_FAIL 0x1 +#define FPIN_LINK_EVT_LOSS_SYNC 0x2 +#define FPIN_LINK_EVT_LOSS_SIG 0x3 +#define FPIN_LINK_EVT_PRIM_SEQ 0x4 +#define FPIN_LINK_EVT_INV_XMT_WD 0x5 +#define FPIN_LINK_EVT_INV_CRC 0x6 +#define FPIN_LINK_EVT_DEV_SPEC 0xF + uint32_t evt_threshold; + uint32_t evt_cnt; + uint32_t port_list_cnt; +}; + +/* The Fabric transmits a Delivery notification to the N_Port ID that sourced + * the impacted frames(s). + */ +struct fpin_delivery_not { + uint32_t ntfy_tag; +#define FPIN_NOTIFY_DELIVERY 0x00020002 + uint32_t ntfy_desc_len; + uint32_t det_pname[2]; + uint32_t att_pname[2]; + uint32_t delivery_reason; +#define FPIN_DEL_EVT_UNKNOWN 0x0 +#define FPIN_DEL_EVT_TMO 0x1 +#define FPIN_DEL_EVT_NO_ROUTE 0x2 +#define FPIN_DEL_EVT_DEV_SPEC 0xf + uint32_t discard_hdr[6]; +}; + +/* The Fabric transmits a Peer Congestion notification to all peer N_Port IDs + * that have registered for FPIN ELS notifications and are within the same zone + * as the impacted N_Port ID. + * The Fabric transmits a Congestion notification to the N_Port ID that sourced + * the impacted frame(s). Congestion Event Types are shared with the Peer + * congestions event types. + * The congestion event types are shared between the Peer and Attached N_Ports. + */ +#define FPIN_CGN_EVT_CLEAR_NONE 0x0 +#define FPIN_CGN_EVT_LOST_CRED 0x1 +#define FPIN_CGN_EVT_CRED_STALL 0x2 +#define FPIN_CGN_EVT_OVERSUB 0x3 +#define FPIN_CGN_EVT_DEV_SPEC 0xF + +struct fpin_peer_cgn_not { + uint32_t ntfy_tag; +#define FPIN_NOTIFY_PEER_CGN 0x00020003 + uint32_t ntfy_desc_len; + uint32_t det_pname[2]; + uint32_t att_pname[2]; + uint32_t word6; +#define fpin_pcgn_evt_type_SHIFT 16 +#define fpin_pcgn_evt_type_MASK 0x0000ffff +#define fpin_pcgn_evt_type_WORD word6 +#define fpin_pcgn_evt_mod_SHIFT 0 +#define fpin_pcgn_evt_mod_MASK 0x0000ffff +#define fpin_pcgn_evt_mod_WORD word6 + uint32_t evt_period; + uint32_t port_list_cnt; +}; + +struct fpin_cgn_not { + uint32_t ntfy_tag; +#define FPIN_NOTIFY_CGN 0x00020004 + uint32_t ntfy_desc_len; + uint32_t word2; +#define fpin_cgn_evt_type_SHIFT 16 +#define fpin_cgn_evt_type_MASK 0x0000ffff +#define fpin_cgn_evt_type_WORD word2 +#define fpin_cgn_evt_mod_SHIFT 0 +#define fpin_cgn_evt_mod_MASK 0x0000ffff +#define fpin_cgn_evt_mod_WORD word2 + uint32_t evt_period; + uint32_t word4; +#define fpin_cgn_sev_not_SHIFT 24 +#define fpin_cgn_sev_not_MASK 0x000000ff +#define fpin_cgn_sev_not_WORD word4 +#define FPIN_SEV_STATUS_WARNING 0xf1 +#define FPIN_SEV_STATUS_ALARM 0xf7 +}; + + union lpfc_wqe { uint32_t words[16]; struct lpfc_wqe_generic generic; @@ -4602,6 +5418,7 @@ union lpfc_wqe { struct fcp_iread64_wqe fcp_iread; struct fcp_iwrite64_wqe fcp_iwrite; struct abort_cmd_wqe abort_cmd; + struct cmf_sync_wqe cmf_sync; struct create_xri_wqe create_xri; struct xmit_bcast64_wqe xmit_bcast64; struct xmit_seq64_wqe xmit_sequence; @@ -4609,10 +5426,11 @@ union lpfc_wqe { struct xmit_els_rsp64_wqe xmit_els_rsp; struct els_request64_wqe els_req; struct gen_req64_wqe gen_req; + struct send_frame_wqe send_frame; struct fcp_trsp64_wqe fcp_trsp; struct fcp_tsend64_wqe fcp_tsend; struct fcp_treceive64_wqe fcp_treceive; - struct send_frame_wqe send_frame; + }; union lpfc_wqe128 { @@ -4622,6 +5440,7 @@ union lpfc_wqe128 { struct fcp_iread64_wqe fcp_iread; struct fcp_iwrite64_wqe fcp_iwrite; struct abort_cmd_wqe abort_cmd; + struct cmf_sync_wqe cmf_sync; struct create_xri_wqe create_xri; struct xmit_bcast64_wqe xmit_bcast64; struct xmit_seq64_wqe xmit_sequence; @@ -4662,6 +5481,7 @@ struct lpfc_grp_hdr { #define FCP_COMMAND_TRSP 0x3 #define FCP_COMMAND_TSEND 0x7 #define OTHER_COMMAND 0x8 +#define CMF_SYNC_COMMAND 0xA #define ELS_COMMAND_NON_FIP 0xC #define ELS_COMMAND_FIP 0xD @@ -4683,6 +5503,7 @@ struct lpfc_grp_hdr { #define CMD_FCP_TRECEIVE64_WQE 0xA1 #define CMD_FCP_TRSP64_WQE 0xA3 #define CMD_GEN_REQUEST64_WQE 0xC2 +#define CMD_CMF_SYNC_WQE 0xE8 #define CMD_WQE_MASK 0xff @@ -4690,3 +5511,308 @@ struct lpfc_grp_hdr { #define LPFC_FW_DUMP 1 #define LPFC_FW_RESET 2 #define LPFC_DV_RESET 3 + +#if !defined(FC_LS_TLV_DTAG_INIT) +/* On an older kernel. Add what should have been in */ + +/* + * Link Service TLV Descriptor Tag Values + */ +enum fc_ls_tlv_dtag { + ELS_DTAG_LS_REQ_INFO = 0x00000001, + /* Link Service Request Information Descriptor */ + ELS_DTAG_LNK_INTEGRITY = 0x00020001, + /* Link Integrity Notification Descriptor */ + ELS_DTAG_DELIVERY = 0x00020002, + /* Delivery Notification Descriptor */ + ELS_DTAG_PEER_CONGEST = 0x00020003, + /* Peer Congestion Notification Descriptor */ + ELS_DTAG_CONGESTION = 0x00020004, + /* Congestion Notification Descriptor */ + ELS_DTAG_FPIN_REGISTER = 0x00030001, + /* FPIN Registration Descriptor */ +}; + +/* + * Initializer useful for decoding table. + * Please keep this in sync with the above definitions. + */ +#define FC_LS_TLV_DTAG_INIT { \ + { ELS_DTAG_LS_REQ_INFO, "Link Service Request Information" }, \ + { ELS_DTAG_LNK_INTEGRITY, "Link Integrity Notification" }, \ + { ELS_DTAG_DELIVERY, "Delivery Notification Present" }, \ + { ELS_DTAG_PEER_CONGEST, "Peer Congestion Notification" }, \ + { ELS_DTAG_CONGESTION, "Congestion Notification" }, \ + { ELS_DTAG_FPIN_REGISTER, "FPIN Registration" }, \ +} + +/* + * Generic Link Service TLV Descriptor format + * + * This structure, as it defines no payload, will also be referred to + * as the "tlv header" - which contains the tag and len fields. + */ +struct fc_tlv_desc { + __be32 desc_tag; /* Notification Descriptor Tag */ + __be32 desc_len; /* Length of Descriptor (in bytes). + * Size of descriptor excluding + * desc_tag and desc_len fields. + */ + __u8 desc_value[0]; /* Descriptor Value */ +}; + +/* Descriptor tag and len fields are considered the mandatory header + * for a descriptor + */ +#define FC_TLV_DESC_HDR_SZ sizeof(struct fc_tlv_desc) + +/* + * Macro, used when initializing payloads, to return the descriptor length. + * Length is size of descriptor minus the tag and len fields. + */ +#define FC_TLV_DESC_LENGTH_FROM_SZ(desc) \ + (sizeof(desc) - FC_TLV_DESC_HDR_SZ) + +/* Macro, used on received payloads, to return the descriptor length */ +#define FC_TLV_DESC_SZ_FROM_LENGTH(tlv) \ + (__be32_to_cpu((tlv)->desc_len) + FC_TLV_DESC_HDR_SZ) + +/* + * This helper is used to walk descriptors in a descriptor list. + * Given the address of the current descriptor, which minimally contains a + * tag and len field, calculate the address of the next descriptor based + * on the len field. + */ +static inline void *fc_tlv_next_desc(void *desc) +{ + struct fc_tlv_desc *tlv = desc; + + return (desc + FC_TLV_DESC_SZ_FROM_LENGTH(tlv)); +} + +enum fc_fpin_li_event_types { + FPIN_LI_UNKNOWN = 0x0, + FPIN_LI_LINK_FAILURE = 0x1, + FPIN_LI_LOSS_OF_SYNC = 0x2, + FPIN_LI_LOSS_OF_SIG = 0x3, + FPIN_LI_PRIM_SEQ_ERR = 0x4, + FPIN_LI_INVALID_TX_WD = 0x5, + FPIN_LI_INVALID_CRC = 0x6, + FPIN_LI_DEVICE_SPEC = 0xF, +}; + +/* + * Initializer useful for decoding table. + * Please keep this in sync with the above definitions. + */ +#define FC_FPIN_LI_EVT_TYPES_INIT { \ + { FPIN_LI_UNKNOWN, "Unknown" }, \ + { FPIN_LI_LINK_FAILURE, "Link Failure" }, \ + { FPIN_LI_LOSS_OF_SYNC, "Loss of Synchronization" }, \ + { FPIN_LI_LOSS_OF_SIG, "Loss of Signal" }, \ + { FPIN_LI_PRIM_SEQ_ERR, "Primitive Sequence Protocol Error" }, \ + { FPIN_LI_INVALID_TX_WD, "Invalid Transmission Word" }, \ + { FPIN_LI_INVALID_CRC, "Invalid CRC" }, \ + { FPIN_LI_DEVICE_SPEC, "Device Specific" }, \ +} + +/* + * Link Integrity Notification Descriptor + */ +struct fc_fn_li_desc { + __be32 desc_tag; /* Descriptor Tag (0x00020001) */ + __be32 desc_len; /* Length of Descriptor (in bytes). + * Size of descriptor excluding + * desc_tag and desc_len fields. + */ + __be64 detecting_wwpn; /* Port Name that detected event */ + __be64 attached_wwpn; /* Port Name of device attached to + * detecting Port Name + */ + __be16 event_type; /* see enum fc_fpin_li_event_types */ + __be16 event_modifier; /* Implementation specific value + * describing the event type + */ + __be32 event_threshold;/* duration in ms of the link + * integrity detection cycle + */ + __be32 event_count; /* minimum number of event + * occurrences during the event + * threshold to caause the LI event + */ + __be32 pname_count; /* number of portname_list elements */ + __be64 pname_list[0]; /* list of N_Port_Names accessible + * through the attached port + */ +}; + +#endif /* !defined(FC_LS_TLV_DTAG_INIT) */ + +#if !defined(FC_FPIN_DELI_EVT_TYPES_INIT) + +enum fc_fpin_deli_event_types { + FPIN_DELI_UNKNOWN = 0x0, + FPIN_DELI_TIMEOUT = 0x1, + FPIN_DELI_UNABLE_TO_ROUTE = 0x2, + FPIN_DELI_DEVICE_SPEC = 0xF, +}; + +/* + * Initializer useful for decoding table. + * Please keep this in sync with the above definitions. + */ +#define FC_FPIN_DELI_EVT_TYPES_INIT { \ + { FPIN_DELI_UNKNOWN, "Unknown" }, \ + { FPIN_DELI_TIMEOUT, "Link Failure" }, \ + { FPIN_DELI_UNABLE_TO_ROUTE, "Loss of Synchronization" }, \ + { FPIN_DELI_DEVICE_SPEC, "Device Specific" }, \ +} + +/* + * Delivery Descriptor + */ +struct fc_fn_deli_desc { + __be32 desc_tag; /* Descriptor Tag (0x00020002) */ + __be32 desc_len; /* Length of Descriptor (in bytes). + * Size of descriptor excluding + * desc_tag and desc_len fields. + */ + __be64 detecting_wwpn; /* Port Name that detected event */ + __be64 attached_wwpn; /* Port Name of device attached to + * detecting Port Name + */ + __be32 deli_reason_code; /* See enum fc_fpin_deli_evt_types + * for values. + */ +}; +#endif /* !defined(FC_FPIN_DELI_EVT_TYPES_INIT) */ + +#if !defined(FC_FPIN_CONGN_EVT_TYPES_INIT) +enum fc_fpin_congn_event_types { + FPIN_CONGN_CLEAR = 0x0, + FPIN_CONGN_LOST_CREDIT = 0x1, + FPIN_CONGN_CREDIT_STALL = 0x2, + FPIN_CONGN_OVERSUBSCRIPTION = 0x3, + FPIN_CONGN_DEVICE_SPEC = 0xF, +}; + +/* + * Initializer useful for decoding table. + * Please keep this in sync with the above definitions. + */ +#define FC_FPIN_CONGN_EVT_TYPES_INIT { \ + { FPIN_CONGN_CLEAR, "None" }, \ + { FPIN_CONGN_LOST_CREDIT, "Lost Credit" }, \ + { FPIN_CONGN_CREDIT_STALL, "Credit Stall" }, \ + { FPIN_CONGN_OVERSUBSCRIPTION, "Oversubscription" }, \ + { FPIN_CONGN_DEVICE_SPEC, "Device Specific" }, \ +} + +/* + * Peer Congestion Notification Descriptor + */ +struct fc_fn_peer_congn_desc { + __be32 desc_tag; /* Descriptor Tag (0x00020003) */ + __be32 desc_len; /* Length of Descriptor (in bytes). + * Size of descriptor excluding + * desc_tag and desc_len fields. + */ + __be64 detecting_wwpn; /* Port Name that detected event */ + __be64 attached_wwpn; /* Port Name of device attached to + * detecting Port Name + */ + __be16 event_type; /* see enum fc_fpin_congn_event_types */ + __be16 event_modifier; /* Implementation specific value + * describing the event type + */ + __be32 event_period; /* duration in ms of the link + * integrity detection cycle + */ + __be32 pname_count; /* number of portname_list elements */ + __be64 pname_list[0]; /* list of N_Port_Names accessible + * through the attached port + */ +}; + +/* + * Congestion Notification Descriptor + */ +struct fc_fn_congn_desc { + __be32 desc_tag; /* Descriptor Tag (0x00020004) */ + __be32 desc_len; /* Length of Descriptor (in bytes). + * Size of descriptor excluding + * desc_tag and desc_len fields. + */ + __be16 event_type; /* see enum fc_fpin_pc_event_types */ + __be16 event_modifier; /* Implementation specific value + * describing the event type + */ + __be32 event_period; /* duration in ms of the link + * integrity detection cycle + */ + __u8 severity; /* Urgency of notification */ + __u8 rsvd[3]; +}; + +#endif /* !defined(FC_FPIN_CONGN_EVT_TYPES_INIT) */ + +enum fc_fpin_congn_sev_types { + FPIN_CONGN_SEV_WARNING = 0xf1, + FPIN_CONGN_SEV_ERROR = 0xf7, +}; + +/* + * Initializer useful for decoding table. + * Please keep this in sync with the above definitions. + */ +#define FC_FPIN_CONGN_SEV_INIT { \ + { FPIN_CONGN_SEV_WARNING, "Warning" }, \ + { FPIN_CONGN_SEV_ERROR, "Alarm" }, \ +} + +/* + * ELS_FPIN - Fabric Performance Impact Notification + */ +struct lpfc_els_fpin { + __u8 fpin_cmd; /* command (0x16) */ + __u8 fpin_zero[3]; /* specified as zero - part of cmd */ + __be32 desc_len; /* Length of Descriptor List (in bytes). + * Size of ELS excluding fpin_cmd, + * fpin_zero and desc_len fields. + */ + struct fc_tlv_desc fpin_desc[0]; /* Descriptor list */ +}; + +/* Used for logging FPIN messages */ +#define LPFC_FPIN_WWPN_LINE_SZ 128 +#define LPFC_FPIN_WWPN_LINE_CNT 6 +#define LPFC_FPIN_WWPN_NUM_LINE 6 + +/* + * Macro that declares tables and a routine to perform enum type to + * ascii string lookup. + * + * Defines a table for an enum. Uses xxx_INIT defines for + * the enum to populate the table. Macro defines a routine (named + * by caller) that will search all elements of the table for the key + * and return the name string if found or "Unrecognized" if not found. + */ +#define DECLARE_ENUM2STR_LOOKUP(routine, enum_name, enum_init) \ +static struct { \ + enum enum_name value; \ + char *name; \ +} fc_##enum_name##_e2str_names[] = enum_init; \ +static const char *(routine)(enum enum_name table_key) \ +{ \ + int i; \ + char *name = "Unrecognized"; \ + \ + for (i = 0; i < ARRAY_SIZE(fc_##enum_name##_e2str_names); i++) {\ + if (fc_##enum_name##_e2str_names[i].value == table_key) {\ + name = fc_##enum_name##_e2str_names[i].name; \ + break; \ + } \ + } \ + return name; \ +} + diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h index d48414e29..8d609bef8 100644 --- a/drivers/scsi/lpfc/lpfc_ids.h +++ b/drivers/scsi/lpfc/lpfc_ids.h @@ -24,62 +24,7 @@ #include const struct pci_device_id lpfc_id_table[] = { - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S, - PCI_ANY_ID, PCI_ANY_ID, }, +#ifndef BUILD_BRCMFCOE {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID, @@ -92,35 +37,29 @@ const struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, - PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC, PCI_ANY_ID, PCI_ANY_ID, }, +#ifndef BUILD_RHEL8 {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE, PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF, - PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, PCI_ANY_ID, PCI_ANY_ID, }, +#endif + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7_FC, PCI_ANY_ID, PCI_ANY_ID, }, +#else + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, PCI_ANY_ID, PCI_ANY_ID, }, +#endif { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b5cee2a2a..aab455a36 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -38,8 +38,8 @@ #include #include #include -#include #include +#include #include #include @@ -49,7 +49,11 @@ #include #include +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -67,6 +71,18 @@ #include "lpfc_version.h" #include "lpfc_ids.h" +/* + * Later versions of the kernel removed support of the + * initialization function macros. In this case, define + * the macros as nops to allow the code to compile + */ + +#ifndef __devinit +#define __devinit +#define __devexit +#define __devexit_p(x) x +#endif + static enum cpuhp_state lpfc_cpuhp_state; /* Used when mapping IRQ vectors in a driver centric manner */ static uint32_t lpfc_present_cpu; @@ -95,6 +111,7 @@ static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t); static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); +static int lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -155,7 +172,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0324 Config Port initialization " "error, mbxCmd x%x READ_NVPARM, " "mbxStatus x%x\n", @@ -179,7 +196,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) lpfc_read_rev(phba, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0439 Adapter failed to init, mbxCmd x%x " "READ_REV, mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); @@ -194,7 +211,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) */ if (mb->un.varRdRev.rr == 0) { vp->rev.rBit = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0440 Adapter failed to init, READ_REV has " "missing revision information.\n"); mempool_free(pmb, phba->mbox_mem_pool); @@ -255,13 +272,15 @@ lpfc_config_port_prep(struct lpfc_hba *phba) */ if (mb->un.varDmp.word_cnt == 0) break; - if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; + + i = mb->un.varDmp.word_cnt * sizeof(uint32_t); + if (offset + i > DMP_VPD_SIZE) + i = DMP_VPD_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - lpfc_vpd_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); + lpfc_vpd_data + offset, i); + offset += i; + } while (offset < DMP_VPD_SIZE); + lpfc_parse_vpd(phba, lpfc_vpd_data, offset); kfree(lpfc_vpd_data); @@ -337,10 +356,8 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) /** * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname, - * cfg_soft_wwnn, cfg_soft_wwpn * @vport: pointer to lpfc vport data structure. * - * * Return codes * None. **/ @@ -350,19 +367,11 @@ lpfc_update_vport_wwn(struct lpfc_vport *vport) uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level; u32 *fawwpn_key = (u32 *)&vport->fc_sparam.un.vendorVersion[0]; - /* If the soft name exists then update it using the service params */ - if (vport->phba->cfg_soft_wwnn) - u64_to_wwn(vport->phba->cfg_soft_wwnn, - vport->fc_sparam.nodeName.u.wwn); - if (vport->phba->cfg_soft_wwpn) - u64_to_wwn(vport->phba->cfg_soft_wwpn, - vport->fc_sparam.portName.u.wwn); - /* - * If the name is empty or there exists a soft name + * If the name is empty * then copy the service params name, otherwise use the fc name */ - if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn) + if (vport->fc_nodename.u.wwn[0] == 0) memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); else @@ -373,19 +382,19 @@ lpfc_update_vport_wwn(struct lpfc_vport *vport) * If the port name has changed, then set the Param changes flag * to unreg the login */ - if (vport->fc_portname.u.wwn[0] != 0 && + if ((vport->fc_portname.u.wwn[0] != 0) && memcmp(&vport->fc_portname, &vport->fc_sparam.portName, sizeof(struct lpfc_name))) vport->vport_flag |= FAWWPN_PARAM_CHG; - if (vport->fc_portname.u.wwn[0] == 0 || - vport->phba->cfg_soft_wwpn || - (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) || - vport->vport_flag & FAWWPN_SET) { + if ((vport->fc_portname.u.wwn[0] == 0) || + (vvvl == 1 && (cpu_to_be32(*fawwpn_key)) == FAPWWN_KEY_VENDOR) || + (vport->vport_flag & FAWWPN_SET)) { memcpy(&vport->fc_portname, &vport->fc_sparam.portName, sizeof(struct lpfc_name)); vport->vport_flag &= ~FAWWPN_SET; - if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) + if (vvvl == 1 && (cpu_to_be32(*fawwpn_key)) == + FAPWWN_KEY_VENDOR) vport->vport_flag |= FAWWPN_SET; } else @@ -444,7 +453,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0448 Adapter failed init, mbxCmd x%x " "READ_SPARM mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); @@ -498,7 +507,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_read_config(phba, pmb); pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0453 Adapter failed to init, mbxCmd x%x " "READ_CONFIG, mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); @@ -511,21 +520,12 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_sli_read_link_ste(phba); /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - i = (mb->un.varRdConfig.max_xri + 1); - if (phba->cfg_hba_queue_depth > i) { + if (phba->cfg_hba_queue_depth > mb->un.varRdConfig.max_xri) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "3359 HBA queue depth changed from %d to %d\n", - phba->cfg_hba_queue_depth, i); - phba->cfg_hba_queue_depth = i; - } - - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - i = (mb->un.varRdConfig.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > i) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3360 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, i); - phba->pport->cfg_lun_queue_depth = i; + phba->cfg_hba_queue_depth, + mb->un.varRdConfig.max_xri); + phba->cfg_hba_queue_depth = mb->un.varRdConfig.max_xri; } phba->lmt = mb->un.varRdConfig.lmt; @@ -556,7 +556,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) } rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0352 Config MSI mailbox command " "failed, mbxCmd x%x, mbxStatus x%x\n", pmb->u.mb.mbxCommand, @@ -600,31 +600,29 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Set up heart beat (HB) timer */ mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); phba->last_completion_time = jiffies; /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); if (phba->hba_flag & LINK_DISABLED) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2598 Adapter Link is disabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2598 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2599 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2599 Adapter failed to issue DOWN_LINK" + " mbox command rc 0x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { mempool_free(pmb, phba->mbox_mem_pool); - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + rc = phba->lpfc_hba_init_link(phba); if (rc) return rc; } @@ -641,9 +639,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0456 Adapter failed to issue " "ASYNCEVT_ENABLE mbox status x%x\n", rc); @@ -663,7 +659,8 @@ lpfc_config_port_post(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0435 Adapter failed " "to get Option ROM version status x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); } @@ -674,7 +671,6 @@ lpfc_config_port_post(struct lpfc_hba *phba) /** * lpfc_hba_init_link - Initialize the FC link * @phba: pointer to lpfc hba data structure. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -686,16 +682,15 @@ lpfc_config_port_post(struct lpfc_hba *phba) * Any other value - error **/ static int -lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) +lpfc_hba_init_link(struct lpfc_hba *phba) { - return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology, flag); + return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology); } /** * lpfc_hba_init_link_fc_topology - Initialize FC link with desired topology * @phba: pointer to lpfc hba data structure. * @fc_topology: desired fc topology. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -707,8 +702,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) * Any other value - error **/ int -lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, - uint32_t flag) +lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *pmb; @@ -741,22 +735,22 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) { /* Reset link speed to auto */ - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1302 Invalid speed for this board:%d " - "Reset link speed to auto.\n", - phba->cfg_link_speed); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "1302 Invalid speed for this board:%d " + "Reset link speed to auto.\n", + phba->cfg_link_speed); phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; } lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (phba->sli_rev < LPFC_SLI_REV4) lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, flag); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0498 Adapter failed to init, mbxCmd x%x " - "INIT_LINK, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0498 Adapter failed to init, mbxCmd x%x " + "INIT_LINK, mbxStatus x%x\n", + mb->mbxCommand, mb->mbxStatus); if (phba->sli_rev <= LPFC_SLI_REV3) { /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); @@ -766,13 +760,11 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, readl(phba->HAregaddr); /* flush */ } phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY || flag == MBX_POLL) + if (rc != MBX_BUSY) mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK; - if (flag == MBX_POLL) - mempool_free(pmb, phba->mbox_mem_pool); return 0; } @@ -780,7 +772,6 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, /** * lpfc_hba_down_link - this routine downs the FC link * @phba: pointer to lpfc hba data structure. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the DOWN_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -791,7 +782,7 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, * Any other value - error **/ static int -lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) +lpfc_hba_down_link(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmb; int rc; @@ -802,24 +793,19 @@ lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) return -ENOMEM; } - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "0491 Adapter Link is disabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0491 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, flag); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2522 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2522 Adapter failed to issue DOWN_LINK" + " mbox command rc 0x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } - if (flag == MBX_POLL) - mempool_free(pmb, phba->mbox_mem_pool); - return 0; } @@ -1146,13 +1132,21 @@ lpfc_hba_down_post(struct lpfc_hba *phba) * be cleared by the worker thread after it has taken the event bitmap out. **/ static void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_hb_timeout(unsigned long ptr) +#else lpfc_hb_timeout(struct timer_list *t) +#endif { struct lpfc_hba *phba; uint32_t tmo_posted; unsigned long iflag; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + phba = (struct lpfc_hba *)ptr; +#else phba = from_timer(phba, t, hb_tmofunc); +#endif /* Check for heart beat timeout conditions */ spin_lock_irqsave(&phba->pport->work_port_lock, iflag); @@ -1180,12 +1174,20 @@ lpfc_hb_timeout(struct timer_list *t) * be cleared by the worker thread after it has taken the event bitmap out. **/ static void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_rrq_timeout(unsigned long ptr) +#else lpfc_rrq_timeout(struct timer_list *t) +#endif { struct lpfc_hba *phba; unsigned long iflag; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + phba = (struct lpfc_hba *)ptr; +#else phba = from_timer(phba, t, rrq_tmr); +#endif spin_lock_irqsave(&phba->pport->work_port_lock, iflag); if (!(phba->pport->load_flag & FC_UNLOADING)) phba->hba_flag |= HBA_RRQ_ACTIVE; @@ -1219,10 +1221,10 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) unsigned long drvr_flag; spin_lock_irqsave(&phba->hbalock, drvr_flag); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - /* Check and reset heart-beat timer is necessary */ + /* Check and reset heart-beat timer if necessary */ mempool_free(pmboxq, phba->mbox_mem_pool); if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && !(phba->link_state == LPFC_HBA_ERROR) && @@ -1233,6 +1235,78 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) return; } +/** + * lpfc_idle_stat_delay_work - idle_stat tracking + * + * This routine tracks per-cq idle_stat and determines polling decisions. + * + * Note: Will skip irq polling decisions if CGN mgt is enabled. + * + * Return codes: + * None + **/ +static void +lpfc_idle_stat_delay_work(struct work_struct *work) +{ + struct lpfc_hba *phba = container_of(to_delayed_work(work), + struct lpfc_hba, + idle_stat_delay_work); + struct lpfc_queue *cq; + struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_idle_stat *idle_stat; + u32 i, idle_percent; + u64 wall, wall_idle, diff_wall, diff_idle, busy_time; + + if (phba->pport->load_flag & FC_UNLOADING) + return; + + if (phba->link_state == LPFC_HBA_ERROR || + phba->pport->fc_flag & FC_OFFLINE_MODE || + phba->cmf_active_mode != LPFC_CFG_OFF) + goto requeue; + + for_each_present_cpu(i) { + hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq]; + cq = hdwq->io_cq; + + /* Skip if we've already handled this cq's primary CPU */ + if (cq->chann != i) + continue; + + idle_stat = &phba->sli4_hba.idle_stat[i]; + + /* get_cpu_idle_time returns values as running counters. Thus, + * to know the amount for this period, the prior counter values + * need to be subtracted from the current counter values. + * From there, the idle time stat can be calculated as a + * percentage of 100 - the sum of the other consumption times. + */ + wall_idle = get_cpu_idle_time(i, &wall, 1); + diff_idle = wall_idle - idle_stat->prev_idle; + diff_wall = wall - idle_stat->prev_wall; + + if (diff_wall <= diff_idle) + busy_time = 0; + else + busy_time = diff_wall - diff_idle; + + idle_percent = div64_u64(100 * busy_time, diff_wall); + idle_percent = 100 - idle_percent; + + if (idle_percent < 15) + cq->poll_mode = LPFC_QUEUE_WORK; + else + cq->poll_mode = LPFC_IRQ_POLL; + + idle_stat->prev_idle = wall_idle; + idle_stat->prev_wall = wall; + } + +requeue: + schedule_delayed_work(&phba->idle_stat_delay_work, + msecs_to_jiffies(LPFC_IDLE_STAT_DELAY)); +} + static void lpfc_hb_eq_delay_work(struct work_struct *work) { @@ -1240,10 +1314,9 @@ lpfc_hb_eq_delay_work(struct work_struct *work) struct lpfc_hba, eq_delay_work); struct lpfc_eq_intr_info *eqi, *eqi_new; struct lpfc_queue *eq, *eq_next; - unsigned char *eqcnt = NULL; + unsigned char *ena_delay = NULL; uint32_t usdelay; int i; - bool update = false; if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING) return; @@ -1252,44 +1325,35 @@ lpfc_hb_eq_delay_work(struct work_struct *work) phba->pport->fc_flag & FC_OFFLINE_MODE) goto requeue; - eqcnt = kcalloc(num_possible_cpus(), sizeof(unsigned char), - GFP_KERNEL); - if (!eqcnt) + ena_delay = kcalloc(phba->sli4_hba.num_possible_cpu, sizeof(*ena_delay), + GFP_KERNEL); + if (!ena_delay) goto requeue; - if (phba->cfg_irq_chann > 1) { - /* Loop thru all IRQ vectors */ - for (i = 0; i < phba->cfg_irq_chann; i++) { - /* Get the EQ corresponding to the IRQ vector */ - eq = phba->sli4_hba.hba_eq_hdl[i].eq; - if (!eq) - continue; - if (eq->q_mode) { - update = true; - break; - } - if (eqcnt[eq->last_cpu] < 2) - eqcnt[eq->last_cpu]++; + for (i = 0; i < phba->cfg_irq_chann; i++) { + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; + if (!eq) + continue; + if (eq->q_mode || eq->q_flag & HBA_EQ_DELAY_CHK) { + eq->q_flag &= ~HBA_EQ_DELAY_CHK; + ena_delay[eq->last_cpu] = 1; } - } else - update = true; + } for_each_present_cpu(i) { eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i); - if (!update && eqcnt[i] < 2) { - eqi->icnt = 0; - continue; + if (ena_delay[i]) { + usdelay = (eqi->icnt >> 10) * LPFC_EQ_DELAY_STEP; + if (usdelay > LPFC_MAX_AUTO_EQ_DELAY) + usdelay = LPFC_MAX_AUTO_EQ_DELAY; + } else { + usdelay = 0; } - - usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) * - LPFC_EQ_DELAY_STEP; - if (usdelay > LPFC_MAX_AUTO_EQ_DELAY) - usdelay = LPFC_MAX_AUTO_EQ_DELAY; - eqi->icnt = 0; list_for_each_entry_safe(eq, eq_next, &eqi->list, cpu_list) { - if (eq->last_cpu != i) { + if (unlikely(eq->last_cpu != i)) { eqi_new = per_cpu_ptr(phba->sli4_hba.eq_info, eq->last_cpu); list_move_tail(&eq->cpu_list, &eqi_new->list); @@ -1301,7 +1365,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work) } } - kfree(eqcnt); + kfree(ena_delay); requeue: queue_delayed_work(phba->wq, &phba->eq_delay_work, @@ -1335,6 +1399,60 @@ static void lpfc_hb_mxp_handler(struct lpfc_hba *phba) } } +/** + * lpfc_issue_hb_mbox - Issues heart-beat mailbox command + * @phba: pointer to lpfc hba data structure. + * + * If a HB mbox is not already in progrees, this routine will allocate + * a LPFC_MBOXQ_t, populate it with a MBX_HEARTBEAT (0x31) command, + * and issue it. The HBA_HBEAT_INP flag means the command is in progress. + **/ +int +lpfc_issue_hb_mbox(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmboxq; + int retval; + + /* Is a Heartbeat mbox already in progress */ + if (phba->hba_flag & HBA_HBEAT_INP) + return 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return -ENOMEM; + + lpfc_heart_beat(phba, pmboxq); + pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; + pmboxq->vport = phba->pport; + retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + + if (retval != MBX_BUSY && retval != MBX_SUCCESS) { + mempool_free(pmboxq, phba->mbox_mem_pool); + return -ENXIO; + } + phba->hba_flag |= HBA_HBEAT_INP; + + return 0; +} + +/** + * lpfc_issue_hb_tmo - Signals heartbeat timer to issue mbox command + * @phba: pointer to lpfc hba data structure. + * + * The heartbeat timer (every 5 sec) will fire. If the HBA_HBEAT_TMO + * flag is set, it will force a MBX_HEARTBEAT mbox command, regardless + * of the value of lpfc_enable_hba_heartbeat. + * If lpfc_enable_hba_heartbeat is set, the timeout routine will always + * try to issue a MBX_HEARTBEAT mbox command. + **/ +void +lpfc_issue_hb_tmo(struct lpfc_hba *phba) +{ + if (phba->cfg_enable_hba_heartbeat) + return; + phba->hba_flag |= HBA_HBEAT_TMO; +} + /** * lpfc_hb_timeout_handler - The HBA-timer timeout handler * @phba: pointer to lpfc hba data structure. @@ -1355,9 +1473,9 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *phba) { struct lpfc_vport **vports; - LPFC_MBOXQ_t *pmboxq; struct lpfc_dmabuf *buf_ptr; - int retval, i; + int retval = 0; + int i, tmo; struct lpfc_sli *psli = &phba->sli; LIST_HEAD(completions); @@ -1379,24 +1497,6 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) (phba->pport->fc_flag & FC_OFFLINE_MODE)) return; - spin_lock_irq(&phba->pport->work_port_lock); - - if (time_after(phba->last_completion_time + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL), - jiffies)) { - spin_unlock_irq(&phba->pport->work_port_lock); - if (!phba->hb_outstanding) - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - else - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); - return; - } - spin_unlock_irq(&phba->pport->work_port_lock); - if (phba->elsbuf_cnt && (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { spin_lock_irq(&phba->hbalock); @@ -1416,37 +1516,43 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) /* If there is no heart beat outstanding, issue a heartbeat command */ if (phba->cfg_enable_hba_heartbeat) { - if (!phba->hb_outstanding) { + /* If IOs are completing, no need to issue a MBX_HEARTBEAT */ + spin_lock_irq(&phba->pport->work_port_lock); + if (time_after(phba->last_completion_time + + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL), + jiffies)) { + spin_unlock_irq(&phba->pport->work_port_lock); + if (phba->hba_flag & HBA_HBEAT_INP) + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + else + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + goto out; + } + spin_unlock_irq(&phba->pport->work_port_lock); + + /* Check if a MBX_HEARTBEAT is already in progress */ + if (phba->hba_flag & HBA_HBEAT_INP) { + /* + * If heart beat timeout called with HBA_HBEAT_INP set + * we need to give the hb mailbox cmd a chance to + * complete or TMO. + */ + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0459 Adapter heartbeat still out" + "standing:last compl time was %d ms.\n", + jiffies_to_msecs(jiffies + - phba->last_completion_time)); + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + } else { if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) && (list_empty(&psli->mboxq))) { - pmboxq = mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * - LPFC_HB_MBOX_INTERVAL)); - return; - } - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, - MBX_NOWAIT); - - if (retval != MBX_BUSY && - retval != MBX_SUCCESS) { - mempool_free(pmboxq, - phba->mbox_mem_pool); - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * - LPFC_HB_MBOX_INTERVAL)); - return; + retval = lpfc_issue_hb_mbox(phba); + if (retval) { + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + goto out; } phba->skipped_hb = 0; - phba->hb_outstanding = 1; } else if (time_before_eq(phba->last_completion_time, phba->skipped_hb)) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -1457,30 +1563,23 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } else phba->skipped_hb = jiffies; - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); - return; - } else { - /* - * If heart beat timeout called with hb_outstanding set - * we need to give the hb mailbox cmd a chance to - * complete or TMO. - */ - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0459 Adapter heartbeat still out" - "standing:last compl time was %d ms.\n", - jiffies_to_msecs(jiffies - - phba->last_completion_time)); - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + goto out; } } else { - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); + /* Check to see if we want to force a MBX_HEARTBEAT */ + if (phba->hba_flag & HBA_HBEAT_TMO) { + retval = lpfc_issue_hb_mbox(phba); + if (retval) + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + else + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + goto out; + } + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); } +out: + mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(tmo)); } /** @@ -1558,11 +1657,11 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) return; } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0479 Deferred Adapter Hardware Error " - "Data: x%x x%x x%x\n", - phba->work_hs, - phba->work_status[0], phba->work_status[1]); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0479 Deferred Adapter Hardware Error " + "Data: x%x x%x x%x\n", + phba->work_hs, phba->work_status[0], + phba->work_status[1]); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI_ACTIVE; @@ -1713,7 +1812,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) temp_event_data.event_code = LPFC_CRIT_TEMP; temp_event_data.data = (uint32_t)temperature; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0406 Adapter maximum temperature exceeded " "(%ld), taking this port offline " "Data: x%x x%x x%x\n", @@ -1724,8 +1823,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(temp_event_data), (char *) &temp_event_data, - SCSI_NL_VID_TYPE_PCI - | PCI_VENDOR_ID_EMULEX); + LPFC_NL_VENDOR_ID); spin_lock_irq(&phba->hbalock); phba->over_temp_state = HBA_OVER_TEMP; @@ -1737,7 +1835,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) * failure is a value other than FFER6. Do not call the offline * twice. This is the adapter hardware error path. */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0457 Adapter Hardware Error " "Data: x%x x%x x%x\n", phba->work_hs, @@ -1747,7 +1845,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) shost = lpfc_shost_from_vport(vport); fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(event_data), (char *) &event_data, - SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); + LPFC_NL_VENDOR_ID); lpfc_offline_eratt(phba); } @@ -1771,6 +1869,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, { int rc; uint32_t intr_mode; + LPFC_MBOXQ_t *mboxq; if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) { @@ -1785,9 +1884,27 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, /* need reset: attempt for port recovery */ if (en_rn_msg) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2887 Reset Needed: Attempting Port " "Recovery...\n"); + + /* If we are no wait, the HBA has been reset and is not + * functional, thus we should clear + * (LPFC_SLI_ACTIVE | LPFC_SLI_MBOX_ACTIVE) flags. + */ + if (mbx_action == LPFC_MBX_NO_WAIT) { + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; + if (phba->sli.mbox_active) { + mboxq = phba->sli.mbox_active; + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + } + spin_unlock_irq(&phba->hbalock); + } + lpfc_offline_prep(phba, mbx_action); lpfc_sli_flush_io_rings(phba); lpfc_offline(phba); @@ -1795,14 +1912,14 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, lpfc_sli4_disable_intr(phba); rc = lpfc_sli_brdrestart(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6309 Failed to restart board\n"); return rc; } /* request and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3175 Failed to enable interrupt\n"); return -EIO; } @@ -1841,7 +1958,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) * we cannot communicate with the pci card anyway. */ if (pci_channel_offline(phba->pcidev)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3166 pci channel is offline\n"); lpfc_sli4_offline_eratt(phba); return; @@ -1864,7 +1981,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) lpfc_sli4_offline_eratt(phba); return; } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "7623 Checking UE recoverable"); for (i = 0; i < phba->sli4_hba.ue_to_sr / 1000; i++) { @@ -1881,7 +1998,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) msleep(1000); } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4827 smphr_port_status x%x : Waited %dSec", smphr_port_status, i); @@ -1899,14 +2016,14 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) LPFC_MBX_NO_WAIT, en_rn_msg); if (rc == 0) return; - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "4215 Failed to recover UE"); break; } } } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "7624 Firmware not ready: Failing UE recovery," " waited %dSec", i); phba->link_state = LPFC_HBA_ERROR; @@ -1919,7 +2036,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) &portstat_reg.word0); /* consider PCI bus read error as pci_channel_offline */ if (pci_rd_rc1 == -EIO) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3151 PCI bus read access failure: x%x\n", readl(phba->sli4_hba.u.if_type2.STATUSregaddr)); lpfc_sli4_offline_eratt(phba); @@ -1928,10 +2045,10 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2889 Port Overtemperature event, " - "taking port offline Data: x%x x%x\n", - reg_err1, reg_err2); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2889 Port Overtemperature event, " + "taking port offline Data: x%x x%x\n", + reg_err1, reg_err2); phba->sfp_alarm |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE; temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; @@ -1953,17 +2070,17 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) } if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3143 Port Down: Firmware Update " "Detected\n"); en_rn_msg = false; } else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3144 Port Down: Debug Dump\n"); else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3145 Port Down: Provisioning\n"); /* If resets are disabled then leave the HBA alone and return */ @@ -1982,7 +2099,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) break; } /* fall through for not able to recover */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3152 Unrecoverable error\n"); phba->link_state = LPFC_HBA_ERROR; break; @@ -2100,8 +2217,8 @@ lpfc_handle_latt_err_exit: lpfc_linkdown(phba); phba->link_state = LPFC_HBA_ERROR; - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); return; } @@ -2463,7 +2580,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_TIGERSHARK: oneConnect = 1; - m = (typeof(m)){"OCe10100", "PCIe", "FCoE"}; + m = (typeof(m)){"OCe10100", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_TOMCAT: oneConnect = 1; @@ -2484,6 +2602,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPe16000", "PCIe", "Obsolete, Unsupported Fibre Channel Adapter"}; break; +#ifndef BUILD_RHEL8 case PCI_DEVICE_ID_LANCER_FCOE: oneConnect = 1; m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; @@ -2493,6 +2612,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"OCe15100", "PCIe", "Obsolete, Unsupported FCoE"}; break; +#endif case PCI_DEVICE_ID_LANCER_G6_FC: m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; break; @@ -2793,6 +2913,8 @@ lpfc_cleanup(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_external_dif_support *dp, *next_dp; + unsigned long iflags; int i = 0; if (phba->link_state > LPFC_LINK_DOWN) @@ -2804,22 +2926,22 @@ lpfc_cleanup(struct lpfc_vport *vport) NLP_STE_UNUSED_NODE); if (!ndlp) continue; - spin_lock_irq(&phba->ndlp_lock); + spin_lock_irqsave(&phba->ndlp_lock, iflags); NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); + spin_unlock_irqrestore(&phba->ndlp_lock, iflags); /* Trigger the release of the ndlp memory */ lpfc_nlp_put(ndlp); continue; } - spin_lock_irq(&phba->ndlp_lock); + spin_lock_irqsave(&phba->ndlp_lock, iflags); if (NLP_CHK_FREE_REQ(ndlp)) { /* The ndlp should not be in memory free mode already */ - spin_unlock_irq(&phba->ndlp_lock); + spin_unlock_irqrestore(&phba->ndlp_lock, iflags); continue; } else /* Indicate request for freeing ndlp memory */ NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); + spin_unlock_irqrestore(&phba->ndlp_lock, iflags); if (vport->port_type != LPFC_PHYSICAL_PORT && ndlp->nlp_DID == Fabric_DID) { @@ -2850,12 +2972,13 @@ lpfc_cleanup(struct lpfc_vport *vport) */ while (!list_empty(&vport->fc_nodes)) { if (i++ > 3000) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0233 Nodelist not empty\n"); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_NODE, + LOG_TRACE_EVENT, "0282 did:x%x ndlp:x%px " "usgmap:x%x refcnt:%d\n", ndlp->nlp_DID, (void *)ndlp, @@ -2869,6 +2992,15 @@ lpfc_cleanup(struct lpfc_vport *vport) msleep(10); } lpfc_cleanup_vports_rrqs(vport, NULL); + + /* Cleanup any discovered External DIF devices for this vport */ + list_for_each_entry_safe(dp, next_dp, &vport->external_dif_list, + listentry) { + spin_lock_irqsave(&vport->external_dif_lock, iflags); + list_del(&dp->listentry); + spin_unlock_irqrestore(&vport->external_dif_lock, iflags); + kfree(dp); + } } /** @@ -2929,6 +3061,138 @@ lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); } +/** + * lpfc_cmf_stop - Stop CMF processing + * @phba: pointer to lpfc hba data structure. + * + * This is called when the link goes down or if CMF mode is turned OFF. + * It is also called when going offline or unloaded just before the + * congestion info buffer is unregistered. + **/ +void +lpfc_cmf_stop(struct lpfc_hba *phba) +{ + int cpu; + struct lpfc_cgn_stat *cgs; + + /* We only do something if CMF is enabled */ + if (!phba->sli4_hba.pc_sli4_params.cmf) + return; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6221 Stop CMF / Cancel Timer\n"); + + /* Cancel the CMF timer */ + hrtimer_cancel(&phba->cmf_timer); + + /* Zero CMF counters */ + atomic_set(&phba->cmf_busy, 0); + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + atomic64_set(&cgs->total_bytes, 0); + atomic64_set(&cgs->rcv_bytes, 0); + atomic_set(&cgs->rx_io_cnt, 0); + atomic64_set(&cgs->rx_latency, 0); + } + atomic_set(&phba->cmf_bw_wait, 0); + + /* Resume any blocked IO - Queue unblock on workqueue */ + queue_work(phba->wq, &phba->unblock_request_work); + +#if defined(BUILD_NVME) + if (phba->nvme_io) + queue_work(phba->nvme_io, &phba->nvme_defer_work); +#endif +} + +static inline uint64_t +lpfc_get_max_line_rate(struct lpfc_hba *phba) +{ + uint64_t rate = lpfc_sli_port_speed_get(phba); + + return ((((unsigned long)rate) * 1024 * 1024) / 10); +} + +void +lpfc_cmf_signal_init(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6223 Signal CMF init\n"); + + /* Use the new fc_linkspeed to recalculate */ + phba->cmf_interval_rate = LPFC_CMF_INTERVAL; + phba->cmf_max_line_rate = lpfc_get_max_line_rate(phba); + phba->cmf_link_byte_count = (phba->cmf_max_line_rate * + phba->cmf_interval_rate) / 1000; + phba->cmf_max_bytes_per_interval = phba->cmf_link_byte_count; + + /* This is a signal to firmware to sync up CMF BW with link speed */ + lpfc_issue_cmf_sync_wqe(phba, 0, 0); +} + +/** + * lpfc_cmf_start - Start CMF processing + * @phba: pointer to lpfc hba data structure. + * + * This is called when the link comes up or if CMF mode is turned OFF + * to Monitor or Managed. + **/ +void +lpfc_cmf_start(struct lpfc_hba *phba) +{ + struct Scsi_Host *shost; + struct lpfc_cgn_stat *cgs; + int cpu; + + /* We only do something if CMF is enabled */ + if (!phba->sli4_hba.pc_sli4_params.cmf || + phba->cmf_active_mode == LPFC_CFG_OFF) + return; + + if (phba->pport) + shost = lpfc_shost_from_vport(phba->pport); + else + shost = NULL; + + /* Reinitialize congestion buffer info */ + lpfc_init_congestion_buf(phba); + + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + + atomic_set(&phba->cmf_busy, 0); + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + atomic64_set(&cgs->total_bytes, 0); + atomic64_set(&cgs->rcv_bytes, 0); + atomic_set(&cgs->rx_io_cnt, 0); + atomic64_set(&cgs->rx_latency, 0); + } + phba->cmf_latency.tv_sec = 0; + phba->cmf_latency.tv_nsec = 0; + + lpfc_cmf_signal_init(phba); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6222 Start CMF / Timer\n"); + + phba->cmf_timer_cnt = 0; + hrtimer_start(&phba->cmf_timer, + ktime_set(0, LPFC_CMF_INTERVAL * 1000000), + HRTIMER_MODE_REL); + /* Setup for latency check in IO cmpl routines */ + ktime_get_real_ts64(&phba->cmf_latency); + + atomic_set(&phba->cmf_bw_wait, 0); + atomic_set(&phba->cmf_stop_io, 0); +#if defined(BUILD_NVME) + if (phba->nvme_io) + queue_work(phba->nvme_io, &phba->nvme_defer_work); +#endif +} + /** * lpfc_stop_hba_timers - Stop all the timers associated with an HBA * @phba: pointer to lpfc hba data structure. @@ -2942,15 +3206,17 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) if (phba->pport) lpfc_stop_vport_timers(phba->pport); cancel_delayed_work_sync(&phba->eq_delay_work); + cancel_delayed_work_sync(&phba->idle_stat_delay_work); del_timer_sync(&phba->sli.mbox_tmo); del_timer_sync(&phba->fabric_block_timer); del_timer_sync(&phba->eratt_poll); del_timer_sync(&phba->hb_tmofunc); + if (phba->sli_rev == LPFC_SLI_REV4) { del_timer_sync(&phba->rrq_tmr); phba->hba_flag &= ~HBA_RRQ_ACTIVE; } - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: @@ -2958,11 +3224,11 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->fcp_poll_timer); break; case LPFC_PCI_DEV_OC: - /* Stop any OneConnect device specific driver timers */ + /* Stop any OneConnect device sepcific driver timers */ lpfc_sli4_stop_fcf_redisc_wait_timer(phba); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0297 Invalid device group (x%x)\n", phba->pci_dev_grp); break; @@ -3009,10 +3275,10 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) /* Check active mailbox complete status every 2ms */ msleep(2); if (time_after(jiffies, timeout)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2813 Mgmt IO is Blocked %x " - "- mbox cmd %x still active\n", - phba->sli.sli_flag, actcmd); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2813 Mgmt IO is Blocked %x " + "- mbox cmd %x still active\n", + phba->sli.sli_flag, actcmd); break; } } @@ -3058,11 +3324,12 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) continue; } ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0009 rpi:%x DID:%x " - "flg:%x map:%x x%px\n", ndlp->nlp_rpi, - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_usg_map, ndlp); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0009 Assign RPI x%x to ndlp x%px " + "DID:x%06x flg:x%x map:x%x\n", + ndlp->nlp_rpi, ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp->nlp_usg_map); } } lpfc_destroy_vport_work_array(phba, vports); @@ -3352,13 +3619,17 @@ lpfc_online(struct lpfc_hba *phba) /* Reestablish the local initiator port. * The offline process destroyed the previous lport. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME && - !phba->nvmet_support) { - error = lpfc_nvme_create_localport(phba->pport); - if (error) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6132 NVME restore reg failed " - "on nvmei error x%x\n", error); + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + if (!phba->nvmet_support) { + error = lpfc_nvme_create_localport(phba->pport); + if (error) { + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "6132 NVME restore reg " + "failed on nvmei error " + "x%x\n", error); + } + } } } else { lpfc_sli_queue_init(phba); @@ -3460,10 +3731,15 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + if ((!NLP_CHK_NODE_ACT(ndlp)) || + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* Driver must assume RPI is invalid for + * any unused or inactive node. + */ + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; continue; + } + if (ndlp->nlp_type & NLP_FABRIC) { lpfc_disc_state_machine(vports[i], ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); @@ -3479,16 +3755,16 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) * comes back online. */ if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_printf_vlog(ndlp->vport, - KERN_INFO, LOG_NODE, - "0011 lpfc_offline: " - "ndlp:x%px did %x " - "usgmap:x%x rpi:%x\n", - ndlp, ndlp->nlp_DID, - ndlp->nlp_usg_map, - ndlp->nlp_rpi); - + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0011 Free RPI x%x on " + "ndlp:x%px did x%x " + "usgmap:x%x\n", + ndlp->nlp_rpi, ndlp, + ndlp->nlp_DID, + ndlp->nlp_usg_map); lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } lpfc_unreg_rpi(vports[i], ndlp); } @@ -3691,7 +3967,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); if (sglq_entry == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2562 Failure to allocate an " "ELS sgl entry:%d\n", i); rc = -ENOMEM; @@ -3702,7 +3979,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) &sglq_entry->phys); if (sglq_entry->virt == NULL) { kfree(sglq_entry); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2563 Failure to allocate an " "ELS mbuf:%d\n", i); rc = -ENOMEM; @@ -3757,7 +4035,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_els_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2400 Failed to allocate xri for " "ELS sgl\n"); rc = -ENOMEM; @@ -3812,7 +4091,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); if (sglq_entry == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6303 Failure to allocate an " "NVMET sgl entry:%d\n", i); rc = -ENOMEM; @@ -3823,7 +4103,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) &sglq_entry->phys); if (sglq_entry->virt == NULL) { kfree(sglq_entry); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6304 Failure to allocate an " "NVMET buf:%d\n", i); rc = -ENOMEM; @@ -3879,7 +4160,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_nvmet_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6307 Failed to allocate xri for " "NVMET sgl\n"); rc = -ENOMEM; @@ -4053,7 +4335,8 @@ lpfc_sli4_io_sgl_update(struct lpfc_hba *phba) &io_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6075 Failed to allocate xri for " "nvme buffer\n"); rc = -ENOMEM; @@ -4123,7 +4406,8 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) && (((unsigned long)(lpfc_ncmd->data) & (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "3369 Memory alignment err: " "addr=%lx\n", (unsigned long)lpfc_ncmd->data); @@ -4152,7 +4436,7 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); kfree(lpfc_ncmd); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6121 Failed to allocate IOTAG for" " XRI:0x%x\n", lxri); lpfc_sli4_free_xri(phba, lxri); @@ -4203,7 +4487,7 @@ lpfc_get_wwpn(struct lpfc_hba *phba) lpfc_read_nv(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6019 Mailbox failed , mbxCmd x%x " "READ_NV, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &mboxq->u.mqe), @@ -4218,7 +4502,9 @@ lpfc_get_wwpn(struct lpfc_hba *phba) if (phba->sli_rev == LPFC_SLI_REV4) return be64_to_cpu(wwn); else - return rol64(wwn, 32); + return (((wwn & 0xffffffff00000000) >> 32) | + ((wwn & 0x00000000ffffffff) << 32)); + } /** @@ -4242,6 +4528,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) { struct lpfc_vport *vport; struct Scsi_Host *shost = NULL; + struct scsi_host_template *template; int error = 0; int i; uint64_t wwn; @@ -4262,7 +4549,8 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) for (i = 0; i < lpfc_no_hba_reset_cnt; i++) { if (wwn == lpfc_no_hba_reset[i]) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6020 Setting use_no_reset port=%llx\n", wwn); use_no_reset_hba = true; @@ -4270,22 +4558,50 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) } } - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { - if (dev != &phba->pcidev->dev) { - shost = scsi_host_alloc(&lpfc_vport_template, - sizeof(struct lpfc_vport)); + /* Seed template for SCSI host registration */ + if (dev == &phba->pcidev->dev) { + template = &phba->port_template; + + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { + /* Seed physical port template */ + memcpy(template, &lpfc_template, sizeof(*template)); + + if (use_no_reset_hba) { + /* template is for a no reset SCSI Host */ + template->max_sectors = 0xffff; + template->eh_host_reset_handler = NULL; + } + + /* Template for all vports this physical port creates */ + memcpy(&phba->vport_template, &lpfc_template, + sizeof(*template)); + phba->vport_template.max_sectors = 0xffff; + phba->vport_template.shost_attrs = lpfc_vport_attrs; + phba->vport_template.eh_bus_reset_handler = NULL; + phba->vport_template.eh_host_reset_handler = NULL; + phba->vport_template.vendor_id = 0; + + /* Initialize the host templates with updated value */ + if (phba->sli_rev == LPFC_SLI_REV4) { + template->sg_tablesize = phba->cfg_scsi_seg_cnt; + phba->vport_template.sg_tablesize = + phba->cfg_scsi_seg_cnt; + } else { + template->sg_tablesize = phba->cfg_sg_seg_cnt; + phba->vport_template.sg_tablesize = + phba->cfg_sg_seg_cnt; + } + } else { - if (!use_no_reset_hba) - shost = scsi_host_alloc(&lpfc_template, - sizeof(struct lpfc_vport)); - else - shost = scsi_host_alloc(&lpfc_template_no_hr, - sizeof(struct lpfc_vport)); + /* NVMET is for physical port only */ + memcpy(template, &lpfc_template_nvme, + sizeof(*template)); } - } else if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - shost = scsi_host_alloc(&lpfc_template_nvme, - sizeof(struct lpfc_vport)); + } else { + template = &phba->vport_template; } + + shost = scsi_host_alloc(template, sizeof(struct lpfc_vport)); if (!shost) goto out; @@ -4306,6 +4622,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->max_cmd_len = 16; if (phba->sli_rev == LPFC_SLI_REV4) { +#if (KERNEL_MAJOR < 5) +#ifndef BUILD_RHEL8 + if (!(shost_use_blk_mq(shost) && phba->cfg_enable_scsi_mq)) + phba->cfg_fcp_mq_threshold = LPFC_FCP_SQ_THRESHOLD; +#endif +#endif if (!phba->cfg_fcp_mq_threshold || phba->cfg_fcp_mq_threshold > phba->cfg_hdw_queue) phba->cfg_fcp_mq_threshold = phba->cfg_hdw_queue; @@ -4320,11 +4642,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->sg_tablesize = LPFC_MAX_SG_TABLESIZE; else shost->sg_tablesize = phba->cfg_scsi_seg_cnt; - } else - /* SLI-3 has a limited number of hardware queues (3), - * thus there is only one for FCP processing. - */ + } else { + /* Always hardcode 1 nr_hw_queue for SLI3 */ shost->nr_hw_queues = 1; + } /* * Set initial can_queue value since 0 is no longer supported and @@ -4340,24 +4661,47 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport->port_type = LPFC_PHYSICAL_PORT; } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, + "9081 CreatePort TMPLATE type %x TBLsize %d " + "SEGcnt %d/%d\n", + vport->port_type, shost->sg_tablesize, + phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt); + /* Initialize all internally managed lists. */ INIT_LIST_HEAD(&vport->fc_nodes); INIT_LIST_HEAD(&vport->rcv_buffer_list); spin_lock_init(&vport->work_port_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&vport->fc_disctmo, lpfc_disc_timeout, + (unsigned long)vport); + + setup_timer(&vport->els_tmofunc, lpfc_els_timeout, + (unsigned long)vport); + + setup_timer(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, + (unsigned long)vport); + +#else timer_setup(&vport->fc_disctmo, lpfc_disc_timeout, 0); timer_setup(&vport->els_tmofunc, lpfc_els_timeout, 0); timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0); +#endif - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) + /* Setup T10-DIF interface with SCSI Layer API */ + if (phba->cfg_enable_bg) lpfc_setup_bg(phba, shost); error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) goto out_put_shost; + /* Initalize objects used to discover External DIF devices */ + INIT_LIST_HEAD(&vport->external_dif_list); + spin_lock_init(&vport->external_dif_lock); + spin_lock_irq(&phba->port_list_lock); list_add_tail(&vport->listentry, &phba->port_list); spin_unlock_irq(&phba->port_list_lock); @@ -4407,10 +4751,11 @@ destroy_port(struct lpfc_vport *vport) int lpfc_get_instance(void) { - int ret; - - ret = idr_alloc(&lpfc_hba_index, NULL, 0, 0, GFP_KERNEL); - return ret < 0 ? -1 : ret; + int instance = 0; + instance = idr_alloc(&lpfc_hba_index, NULL, 0, 0, GFP_KERNEL ); + if (instance < 0) + return -1; + return instance; } /** @@ -4478,6 +4823,13 @@ static void lpfc_host_supported_speeds_set(struct Scsi_Host *shost) struct lpfc_hba *phba = vport->phba; fc_host_supported_speeds(shost) = 0; + /* + * Avoid reporting supported link speed for FCoE as it can't be + * controlled via FCoE. + */ + if (phba->hba_flag & HBA_FCOE_MODE) + return; + if (phba->lmt & LMT_128Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_128GBIT; if (phba->lmt & LMT_64Gb) @@ -4531,8 +4883,6 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) (((uint32_t) vport->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | (uint32_t) vport->fc_sparam.cmn.bbRcvSizeLsb; - fc_host_dev_loss_tmo(shost) = vport->cfg_devloss_tmo; - /* This value is also unchanging */ memset(fc_host_active_fc4s(shost), 0, sizeof(fc_host_active_fc4s(shost))); @@ -4634,9 +4984,17 @@ lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba) * worker thread context. **/ static void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr) +#else lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_hba *phba = (struct lpfc_hba *)ptr; +#else struct lpfc_hba *phba = from_timer(phba, t, fcf.redisc_wait); +#endif /* Don't send FCF rediscovery event if timer cancelled */ spin_lock_irq(&phba->hbalock); @@ -4673,7 +5031,7 @@ lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba, case LPFC_ASYNC_LINK_FAULT_LR_LRR: break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0398 Unknown link fault code: x%x\n", bf_get(lpfc_acqe_link_fault, acqe_link)); break; @@ -4709,7 +5067,7 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba, att_type = LPFC_ATT_LINK_UP; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0399 Invalid link attention type: x%x\n", bf_get(lpfc_acqe_link_status, acqe_link)); att_type = LPFC_ATT_RESERVED; @@ -4811,6 +5169,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_ASYNC_LINK_SPEED_40GBPS: port_speed = 40000; break; + case LPFC_ASYNC_LINK_SPEED_100GBPS: + port_speed = 100000; + break; default: port_speed = 0; } @@ -4881,19 +5242,19 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->fcoe_eventtag = acqe_link->event_tag; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0395 The mboxq allocation failed\n"); return; } mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0396 The lpfc_dmabuf allocation failed\n"); goto out_free_pmb; } mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0397 The mbuf allocation failed\n"); goto out_free_dmabuf; } @@ -5041,6 +5402,659 @@ lpfc_async_link_speed_to_read_top(struct lpfc_hba *phba, uint8_t speed_code) return port_speed; } +void +lpfc_cgn_dump_rxmonitor(struct lpfc_hba *phba) +{ + struct rxtable_entry *entry; + int cnt = 0, head, tail, last, start; + + head = atomic_read(&phba->rxtable_idx_head); + tail = atomic_read(&phba->rxtable_idx_tail); + if (head == tail) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "4411 Rxtable is empty\n"); + return; + } + last = tail; + start = head; + + /* Display the last LPFC_MAX_RXMONITOR_DUMP entries from the rxtable */ + while (start != last) { + if (start) + start--; + else + start = LPFC_MAX_RXMONITOR_ENTRY - 1; + entry = &phba->rxtable[start]; + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "4410 %02d: MBPI %lld Xmit %lld Cmpl %lld " + "Lat %lld ASz %lld Info %02d BWUtil %d " + "Int %d slot %d\n", + cnt, entry->max_bytes_per_interval, + entry->total_bytes, entry->rcv_bytes, + entry->avg_io_latency, entry->avg_io_size, + entry->cmf_info, entry->timer_utilization, + entry->timer_interval, start); + cnt++; + if (cnt >= LPFC_MAX_RXMONITOR_DUMP) + return; + } +} + +/** + * lpfc_cgn_update_stat - Save data into congestion stats buffer + * @phba: pointer to lpfc hba data structure. + * @dtag: FPIN descriptor received + * + * Increment the FPIN received counter/time when it happens. + */ +void +lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag) +{ + struct lpfc_cgn_info *cp; + struct tm broken; + struct timespec64 cur_time; + u32 cnt; + u16 value; + + /* Make sure we have a congestion info buffer */ + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + + /* Update congestion statistics */ + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + cnt = le32_to_cpu(cp->link_integ_notification); + cnt++; + cp->link_integ_notification = cpu_to_le32(cnt); + + cp->cgn_stat_lnk_month = broken.tm_mon + 1; + cp->cgn_stat_lnk_day = broken.tm_mday; + cp->cgn_stat_lnk_year = broken.tm_year - 100; + cp->cgn_stat_lnk_hour = broken.tm_hour; + cp->cgn_stat_lnk_min = broken.tm_min; + cp->cgn_stat_lnk_sec = broken.tm_sec; + break; + case ELS_DTAG_DELIVERY: + cnt = le32_to_cpu(cp->delivery_notification); + cnt++; + cp->delivery_notification = cpu_to_le32(cnt); + + cp->cgn_stat_del_month = broken.tm_mon + 1; + cp->cgn_stat_del_day = broken.tm_mday; + cp->cgn_stat_del_year = broken.tm_year - 100; + cp->cgn_stat_del_hour = broken.tm_hour; + cp->cgn_stat_del_min = broken.tm_min; + cp->cgn_stat_del_sec = broken.tm_sec; + break; + case ELS_DTAG_PEER_CONGEST: + cnt = le32_to_cpu(cp->cgn_peer_notification); + cnt++; + cp->cgn_peer_notification = cpu_to_le32(cnt); + + cp->cgn_stat_peer_month = broken.tm_mon + 1; + cp->cgn_stat_peer_day = broken.tm_mday; + cp->cgn_stat_peer_year = broken.tm_year - 100; + cp->cgn_stat_peer_hour = broken.tm_hour; + cp->cgn_stat_peer_min = broken.tm_min; + cp->cgn_stat_peer_sec = broken.tm_sec; + break; + case ELS_DTAG_CONGESTION: + cnt = le32_to_cpu(cp->cgn_notification); + cnt++; + cp->cgn_notification = cpu_to_le32(cnt); + + cp->cgn_stat_cgn_month = broken.tm_mon + 1; + cp->cgn_stat_cgn_day = broken.tm_mday; + cp->cgn_stat_cgn_year = broken.tm_year - 100; + cp->cgn_stat_cgn_hour = broken.tm_hour; + cp->cgn_stat_cgn_min = broken.tm_min; + cp->cgn_stat_cgn_sec = broken.tm_sec; + } + if (phba->cgn_fpin_frequency && + phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) { + value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency; + cp->cgn_stat_npm = cpu_to_le32(value); + } + value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(value); +} + +/** + * lpfc_cgn_save_evt_cnt - Save data into registered congestion buffer + * @phba: pointer to lpfc hba data structure. + * + * Save the congestion event data every minute. + * On the hour collapse all the minute data into hour data. Every day + * collapse all the hour data into daily data. Separate driver + * and fabrc congestion event counters that will be saved out + * to the registered congestion buffer every minute. + */ +void +lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct tm broken; + struct timespec64 cur_time; + uint32_t i, index; + uint16_t value, mvalue; + uint64_t bps; + uint32_t mbps; + uint32_t dvalue, wvalue, lvalue, avalue; + uint64_t latsum; + uint16_t *ptr; + uint32_t *lptr; + uint16_t *mptr; + + /* Make sure we have a congestion info buffer */ + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + if (time_before(jiffies, phba->cgn_evt_timestamp)) + return; + phba->cgn_evt_timestamp = jiffies + + msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN); + phba->cgn_evt_minute++; + + /* We should get to this point in the routine on 1 minute intervals */ + + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + + if (phba->cgn_fpin_frequency && + phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) { + value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency; + cp->cgn_stat_npm = cpu_to_le32(value); + } + + /* Read and clear the latency counters for this minute */ + lvalue = atomic_read(&phba->cgn_latency_evt_cnt); + latsum = atomic64_read(&phba->cgn_latency_evt); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + + /* We need to store MB/sec bandwidth in the congestion information. + * block_cnt is count of 512 byte blocks for the entire minute, + * bps will get bytes per sec before finally converting to MB/sec. + */ + bps = ((phba->rx_block_cnt / LPFC_SEC_MIN) * 512); + phba->rx_block_cnt = 0; + mvalue = bps / (1024 * 1024); /* convert to MB/sec */ + + /* Every minute */ + /* cgn parameters */ + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_acr = phba->cgn_p.cgn_param_acr; + cp->cgn_info_rxburst = phba->cgn_p.cgn_param_rxburst; + cp->cgn_info_rxbw = phba->cgn_p.cgn_param_rxbw; + + /* Fill in default LUN qdepth */ + value = (uint16_t)(phba->pport->cfg_lun_queue_depth); + cp->cgn_lunq = cpu_to_le16(value); + + /* Record congestion buffer info - every minute + * cgn_driver_evt_cnt (Driver events) + * cgn_fabric_warn_cnt (Congestion Warnings) + * cgn_latency_evt_cnt / cgn_latency_evt (IO Latency) + * cgn_fabric_alarm_cnt (Congestion Alarms) + */ + index = ++cp->cgn_index_minute; + if (cp->cgn_index_minute == LPFC_MIN_HOUR) { + cp->cgn_index_minute = 0; + index = 0; + } + + /* Get the number of driver events in this sample and reset counter */ + dvalue = atomic_read(&phba->cgn_driver_evt_cnt); + atomic_set(&phba->cgn_driver_evt_cnt, 0); + + /* Get the number of warning events - FPIN and Signal for this minute */ + wvalue = 0; + if ((phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + wvalue = atomic_read(&phba->cgn_fabric_warn_cnt); + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + + /* Get the number of alarm events - FPIN and Signal for this minute */ + avalue = 0; + if ((phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + avalue = atomic_read(&phba->cgn_fabric_alarm_cnt); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + + /* Collect the driver, warning, alarm and latency counts for this + * minute into the driver congestion buffer. + */ + ptr = &cp->cgn_drvr_min[index]; + value = (uint16_t)dvalue; + *ptr = cpu_to_le16(value); + + ptr = &cp->cgn_warn_min[index]; + value = (uint16_t)wvalue; + *ptr = cpu_to_le16(value); + + ptr = &cp->cgn_alarm_min[index]; + value = (uint16_t)avalue; + *ptr = cpu_to_le16(value); + + lptr = &cp->cgn_latency_min[index]; + if (lvalue) { + lvalue = (uint32_t)(latsum / lvalue); + *lptr = cpu_to_le32(lvalue); + } else { + *lptr = 0; + } + + /* Collect the bandwidth value into the driver's congesion buffer. */ + mptr = &cp->cgn_bw_min[index]; + *mptr = cpu_to_le16(mvalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2418 Congestion Info - minute (%d): %d %d %d %d %d\n", + index, dvalue, wvalue, *lptr, mvalue, avalue); + + /* Every hour */ + if ((phba->cgn_evt_minute % LPFC_MIN_HOUR) == 0) { + /* Record congestion buffer info - every hour + * Collapse all minutes into an hour + */ + index = ++cp->cgn_index_hour; + if (cp->cgn_index_hour == LPFC_HOUR_DAY) { + cp->cgn_index_hour = 0; + index = 0; + } + + dvalue = 0; + wvalue = 0; + lvalue = 0; + avalue = 0; + mvalue = 0; + mbps = 0; + for (i = 0; i < LPFC_MIN_HOUR; i++) { + dvalue += le16_to_cpu(cp->cgn_drvr_min[i]); + wvalue += le16_to_cpu(cp->cgn_warn_min[i]); + lvalue += le32_to_cpu(cp->cgn_latency_min[i]); + mbps += le16_to_cpu(cp->cgn_bw_min[i]); + avalue += le16_to_cpu(cp->cgn_alarm_min[i]); + } + if (lvalue) /* Avg of latency averages */ + lvalue /= LPFC_MIN_HOUR; + if (mbps) /* Avg of Bandwidth averages */ + mvalue = mbps / LPFC_MIN_HOUR; + + lptr = &cp->cgn_drvr_hr[index]; + *lptr = cpu_to_le32(dvalue); + lptr = &cp->cgn_warn_hr[index]; + *lptr = cpu_to_le32(wvalue); + lptr = &cp->cgn_latency_hr[index]; + *lptr = cpu_to_le32(lvalue); + mptr = &cp->cgn_bw_hr[index]; + *mptr = cpu_to_le16(mvalue); + lptr = &cp->cgn_alarm_hr[index]; + *lptr = cpu_to_le32(avalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2419 Congestion Info - hour " + "(%d): %d %d %d %d %d\n", + index, dvalue, wvalue, lvalue, mvalue, avalue); + } + + /* Every day */ + if ((phba->cgn_evt_minute % LPFC_MIN_DAY) == 0) { + /* Record congestion buffer info - every hour + * Collapse all hours into a day. Rotate days + * after LPFC_MAX_CGN_DAYS. + */ + index = ++cp->cgn_index_day; + if (cp->cgn_index_day == LPFC_MAX_CGN_DAYS) { + cp->cgn_index_day = 0; + index = 0; + } + + /* Anytime we overwrite daily index 0, after we wrap, + * we will be overwriting the oldest day, so we must + * update the congestion data start time for that day. + * That start time should have previously been saved after + * we wrote the last days worth of data. + */ + if ((phba->hba_flag & HBA_CGN_DAY_WRAP) && index == 0) { + time64_to_tm(phba->cgn_daily_ts.tv_sec, 0, &broken); + cp->cgn_info_month = broken.tm_mon + 1; + cp->cgn_info_day = broken.tm_mday; + cp->cgn_info_year = broken.tm_year - 100; + cp->cgn_info_hour = broken.tm_hour; + cp->cgn_info_minute = broken.tm_min; + cp->cgn_info_second = broken.tm_sec; + + lpfc_printf_log + (phba, KERN_INFO, LOG_CGN_MGMT, + "2646 CGNInfo idx0 Start Time: " + "%d/%d/%d %d:%d:%d\n", + cp->cgn_info_day, cp->cgn_info_month, + cp->cgn_info_year, cp->cgn_info_hour, + cp->cgn_info_minute, cp->cgn_info_second); + } + + dvalue = 0; + wvalue = 0; + lvalue = 0; + mvalue = 0; + mbps = 0; + avalue = 0; + for (i = 0; i < LPFC_HOUR_DAY; i++) { + dvalue += le32_to_cpu(cp->cgn_drvr_hr[i]); + wvalue += le32_to_cpu(cp->cgn_warn_hr[i]); + lvalue += le32_to_cpu(cp->cgn_latency_hr[i]); + mbps += le32_to_cpu(cp->cgn_bw_hr[i]); + avalue += le32_to_cpu(cp->cgn_alarm_hr[i]); + } + if (lvalue) /* Avg of latency averages */ + lvalue /= LPFC_HOUR_DAY; + if (mbps) /* Avg of Bandwidth averages */ + mvalue = mbps / LPFC_HOUR_DAY; + + lptr = &cp->cgn_drvr_day[index]; + *lptr = cpu_to_le32(dvalue); + lptr = &cp->cgn_warn_day[index]; + *lptr = cpu_to_le32(wvalue); + lptr = &cp->cgn_latency_day[index]; + *lptr = cpu_to_le32(lvalue); + mptr = &cp->cgn_bw_day[index]; + *mptr = cpu_to_le16(mvalue); + lptr = &cp->cgn_alarm_day[index]; + *lptr = cpu_to_le32(avalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2420 Congestion Info - daily (%d): " + "%d %d %d %d %d\n", + index, dvalue, wvalue, lvalue, mvalue, avalue); + + /* We just wrote LPFC_MAX_CGN_DAYS of data, + * so we are wrapped on any data after this. + * Save this as the start time for the next day. + */ + if (index == (LPFC_MAX_CGN_DAYS - 1)) { + phba->hba_flag |= HBA_CGN_DAY_WRAP; + ktime_get_real_ts64(&phba->cgn_daily_ts); + } + } + + /* Use the frequency found in the last rcv'ed FPIN */ + value = phba->cgn_fpin_frequency; + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) + cp->cgn_warn_freq = cpu_to_le16(value); + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) + cp->cgn_alarm_freq = cpu_to_le16(value); + + /* Frequency (in ms) Signal Warning/Signal Congestion Notifications + * are received by the HBA + */ + value = phba->cgn_sig_freq; + + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + cp->cgn_warn_freq = cpu_to_le16(value); + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) + cp->cgn_alarm_freq = cpu_to_le16(value); + + lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(lvalue); +} + +/** + * lpfc_calc_cmf_latency - latency from start of rxate timer interval + * @phba: The Hba for which this call is being executed. + * + * The routine calculates the latency from the beginning of the CMF timer + * inteval to the current point in time. It is called from IO completion + * when we exceed our Bandwidth limitation for the time interval. + */ +uint32_t +lpfc_calc_cmf_latency(struct lpfc_hba *phba) +{ + struct timespec64 cmpl_time; + uint32_t msec = 0; + + ktime_get_real_ts64(&cmpl_time); + + /* This routine works on a ms granularity so sec and usec are + * converted accordingly. + */ + if (cmpl_time.tv_sec == phba->cmf_latency.tv_sec) { + msec = (cmpl_time.tv_nsec - phba->cmf_latency.tv_nsec) / + NSEC_PER_MSEC; + } else { + if (cmpl_time.tv_nsec >= phba->cmf_latency.tv_nsec) { + msec = (cmpl_time.tv_sec - + phba->cmf_latency.tv_sec) * MSEC_PER_SEC; + msec += ((cmpl_time.tv_nsec - + phba->cmf_latency.tv_nsec) / NSEC_PER_MSEC); + } else { + msec = (cmpl_time.tv_sec - phba->cmf_latency.tv_sec - + 1) * MSEC_PER_SEC; + msec += (((NSEC_PER_SEC - phba->cmf_latency.tv_nsec) + + cmpl_time.tv_nsec) / NSEC_PER_MSEC); + } + } + return msec; +} + +/** + * lpfc_cmf_timer - This is the timer function for one congestion + * rate interval. + */ +enum hrtimer_restart +lpfc_cmf_timer(struct hrtimer *timer) +{ + struct lpfc_hba *phba = container_of(timer, struct lpfc_hba, + cmf_timer); + struct rxtable_entry *entry; + uint32_t io_cnt; + uint32_t head, tail; + uint32_t busy, max_read; + uint64_t total, rcv, lat, mbpi, extra; + int timer_interval = LPFC_CMF_INTERVAL; + uint32_t ms; + struct lpfc_cgn_stat *cgs; + int cpu; + + /* Only restart the timer if congestion mgmt is on */ + if (phba->cmf_active_mode == LPFC_CFG_OFF || + !phba->cmf_latency.tv_sec) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6224 CMF timer exit: %d %lld\n", + phba->cmf_active_mode, + (uint64_t)phba->cmf_latency.tv_sec); + return HRTIMER_NORESTART; + } + + /* If pport is not ready yet, just exit and wait for + * the next timer cycle to hit. + */ + if (!phba->pport) + goto skip; + + /* Do not block SCSI IO while in the timer routine since + * total_bytes will be cleared + */ + atomic_set(&phba->cmf_stop_io, 1); + + /* First we need to calculate the actual ms between + * the last timer interrupt and this one. We ask for + * LPFC_CMF_INTERVAL, however the actual time may + * vary depending on system overhead. + */ + ms = lpfc_calc_cmf_latency(phba); + + /* Immediately after we calculate the time since the last + * timer interrupt, set the start time for the next + * interrupt + */ + ktime_get_real_ts64(&phba->cmf_latency); + + phba->cmf_link_byte_count = + (phba->cmf_max_line_rate * LPFC_CMF_INTERVAL) / 1000; + + /* Collect all the stats from the prior timer interval */ + total = 0; + io_cnt = 0; + lat = 0; + rcv = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_xchg(&cgs->total_bytes, 0); + io_cnt += atomic_xchg(&cgs->rx_io_cnt, 0); + lat += atomic64_xchg(&cgs->rx_latency, 0); + rcv += atomic64_xchg(&cgs->rcv_bytes, 0); + } + + /* Before we issue another CMF_SYNC_WQE, retrieve the BW + * returned from the last CMF_SYNC_WQE issued, from + * cmf_last_sync_bw. This will be the target BW for + * this next timer interval. + */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED && + phba->link_state != LPFC_LINK_DOWN && + phba->hba_flag & HBA_SETUP) { + mbpi = phba->cmf_last_sync_bw; + phba->cmf_last_sync_bw = 0; + extra = 0; + + /* Calculate any extra bytes needed to account for the + * timer accuracy. If we are less than LPFC_CMF_INTERVAL + * add an extra 2% slop factor, equal to LPFC_CMF_INTERVAL + * add an extra 1%. The goal is to equalize total with a + * time > LPFC_CMF_INTERVAL or <= LPFC_CMF_INTERVAL + 1 + */ + if (ms == LPFC_CMF_INTERVAL) + extra = div_u64(total, 100); + else if (ms < LPFC_CMF_INTERVAL) + extra = div_u64(total, 50); + lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra); + } else { + /* For Monitor mode or link down we want mbpi + * to be the full link speed + */ + mbpi = phba->cmf_link_byte_count; + } + phba->cmf_timer_cnt++; + + if (io_cnt) { + /* Update congestion info buffer latency in us */ + atomic_add(io_cnt, &phba->cgn_latency_evt_cnt); + atomic64_add(lat, &phba->cgn_latency_evt); + } + busy = atomic_xchg(&phba->cmf_busy, 0); + max_read = atomic_xchg(&phba->rx_max_read_cnt, 0); + + /* Calculate MBPI for the next timer interval */ + if (mbpi) { + if (mbpi > phba->cmf_link_byte_count || + phba->cmf_active_mode == LPFC_CFG_MONITOR) + mbpi = phba->cmf_link_byte_count; + + /* Change max_bytes_per_interval to what the prior + * CMF_SYNC_WQE cmpl indicated. + */ + if (mbpi != phba->cmf_max_bytes_per_interval) + phba->cmf_max_bytes_per_interval = mbpi; + } + + /* Save rxmonitor information for debug */ + if (phba->rxtable) { + head = atomic_xchg(&phba->rxtable_idx_head, + LPFC_RXMONITOR_TABLE_IN_USE); + entry = &phba->rxtable[head]; + entry->total_bytes = total; + entry->rcv_bytes = rcv; + entry->cmf_busy = busy; + entry->cmf_info = phba->cmf_active_info; + if (io_cnt) { + entry->avg_io_latency = lat / io_cnt; + entry->avg_io_size = rcv / io_cnt; + } else { + entry->avg_io_latency = 0; + entry->avg_io_size = 0; + } + entry->max_read_cnt = max_read; + entry->io_cnt = io_cnt; + entry->max_bytes_per_interval = mbpi; + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + entry->timer_utilization = phba->cmf_last_ts; + else + entry->timer_utilization = ms; + entry->timer_interval = ms; + phba->cmf_last_ts = 0; + + /* Increment rxtable index */ + head = (head + 1) % LPFC_MAX_RXMONITOR_ENTRY; + tail = atomic_read(&phba->rxtable_idx_tail); + if (head == tail) { + tail = (tail + 1) % LPFC_MAX_RXMONITOR_ENTRY; + atomic_set(&phba->rxtable_idx_tail, tail); + } + atomic_set(&phba->rxtable_idx_head, head); + } + + if (phba->cmf_active_mode == LPFC_CFG_MONITOR) { + /* If Monitor mode, check if we are oversubscribed + * against the full line rate. + */ + if (mbpi && total > mbpi) + atomic_inc(&phba->cgn_driver_evt_cnt); + } + phba->rx_block_cnt += (rcv / 512); /* save 512 byte block cnt */ + + /* Each minute save Fabric and Driver congestion information */ + lpfc_cgn_save_evt_cnt(phba); + + /* Since we need to call lpfc_cgn_save_evt_cnt every minute, on the + * minute, adjust our next timer interval, if needed, to ensure a + * 1 minute granularity when we get the next timer interrupt. + */ + if (time_after(jiffies + msecs_to_jiffies(LPFC_CMF_INTERVAL), + phba->cgn_evt_timestamp)) { + timer_interval = jiffies_to_msecs(phba->cgn_evt_timestamp - + jiffies); + if (timer_interval <= 0) + timer_interval = LPFC_CMF_INTERVAL; + + /* If we adjust timer_interval, max_bytes_per_interval + * needs to be adjusted as well. + */ + phba->cmf_link_byte_count = (phba->cmf_max_line_rate * + timer_interval) / 1000; + if (phba->cmf_active_mode == LPFC_CFG_MONITOR) + phba->cmf_max_bytes_per_interval = + phba->cmf_link_byte_count; + } + + /* Since total_bytes has aleady been zero'ed, its okay to unblock + * after max_bytes_per_interval is setup. + */ + if (atomic_xchg(&phba->cmf_bw_wait, 0)) + queue_work(phba->wq, &phba->unblock_request_work); + +#if defined(BUILD_NVME) + if (phba->nvme_io) + queue_work(phba->nvme_io, &phba->nvme_defer_work); +#endif + + /* SCSI IO is now unblocked */ + atomic_set(&phba->cmf_stop_io, 0); + +skip: + hrtimer_forward_now(timer, + ktime_set(0, timer_interval * NSEC_PER_MSEC)); + return HRTIMER_RESTART; +} + #define trunk_link_status(__idx)\ bf_get(lpfc_acqe_fc_la_trunk_config_port##__idx, acqe_fc) ?\ ((phba->trunk_link.link##__idx.state == LPFC_LINK_UP) ?\ @@ -5094,17 +6108,21 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, phba->trunk_link.link3.fault = port_fault & 0x8 ? err : 0; } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2910 Async FC Trunking Event - Speed:%d\n" + phba->fc_eventTag = acqe_fc->event_tag; + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + "2910 Async FC Trunking Event %d - Speed:%d\n" "\tLogical speed:%d " "port0: %s port1: %s port2: %s port3: %s\n", - phba->sli4_hba.link_state.speed, + phba->fc_eventTag, phba->sli4_hba.link_state.speed, phba->sli4_hba.link_state.logical_speed, trunk_link_status(0), trunk_link_status(1), trunk_link_status(2), trunk_link_status(3)); + if (phba->cmf_active_mode != LPFC_CFG_OFF) + lpfc_cmf_signal_init(phba); + if (port_fault) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "3202 trunk error:0x%x (%s) seen on port0:%s " /* * SLI-4: We have only 0xA error codes @@ -5138,7 +6156,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) if (bf_get(lpfc_trailer_type, acqe_fc) != LPFC_FC_LA_EVENT_TYPE_FC_LINK) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2895 Non FC link Event detected.(%d)\n", bf_get(lpfc_trailer_type, acqe_fc)); return; @@ -5186,19 +6204,19 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) phba->sli4_hba.link_state.fault); pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2897 The mboxq allocation failed\n"); return; } mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2898 The lpfc_dmabuf allocation failed\n"); goto out_free_pmb; } mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2899 The mbuf allocation failed\n"); goto out_free_dmabuf; } @@ -5284,22 +6302,22 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) uint8_t operational = 0; struct temp_event temp_event_data; struct lpfc_acqe_misconfigured_event *misconfigured; + struct lpfc_acqe_cgn_signal *cgn_signal; struct Scsi_Host *shost; struct lpfc_vport **vports; - int rc, i; + int rc, i, cnt; evt_type = bf_get(lpfc_trailer_type, acqe_sli); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2901 Async SLI event - Event Data1:x%08x Event Data2:" - "x%08x SLI Event Type:%d\n", + "2901 Async SLI event - Type:%d, Event Data: x%08x " + "x%08x x%08x x%08x\n", evt_type, acqe_sli->event_data1, acqe_sli->event_data2, - evt_type); + acqe_sli->reserved, acqe_sli->trailer); port_name = phba->Port[0]; if (port_name == 0x00) port_name = '?'; /* get port name is empty */ - switch (evt_type) { case LPFC_SLI_EVENT_TYPE_OVER_TEMP: temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; @@ -5365,10 +6383,10 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) &misconfigured->theEvent); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3296 " - "LPFC_SLI_EVENT_TYPE_MISCONFIGURED " - "event: Invalid link %d", + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3296 LPFC_SLI_EVENT_TYPE_" + "MISCONFIGURED event: " + "Invalid link %d", phba->sli4_hba.lnk_info.lnk_no); return; } @@ -5417,7 +6435,8 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) rc = lpfc_sli4_read_config(phba); if (rc) { phba->lmt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "3194 Unable to retrieve supported " "speeds, rc = 0x%x\n", rc); } @@ -5441,11 +6460,62 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "Event Data1:x%08x Event Data2: x%08x\n", acqe_sli->event_data1, acqe_sli->event_data2); break; + case LPFC_SLI_EVENT_TYPE_PORT_PARAMS_CHG: + /* Call FW to obtain active parms */ + lpfc_sli4_cgn_parm_chg_evt(phba); + break; + case LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN: + /* Misconfigured WWN. Reports that the SLI Port is configured + * to use FA-WWN, but the attached device doesn’t support it. + * No driver action is required. + * Event Data1 - N.A, Event Data2 - N.A + */ + lpfc_log_msg(phba, KERN_WARNING, LOG_SLI, + "2699 Misconfigured FA-WWN - Attached device does " + "not support FA-WWN\n"); + break; + case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE: + /* EEPROM failure. No driver action is required */ + lpfc_log_msg(phba, KERN_WARNING, LOG_SLI, + "2518 EEPROM failure - " + "Event Data1: x%08x Event Data2: x%08x\n", + acqe_sli->event_data1, acqe_sli->event_data2); + break; + case LPFC_SLI_EVENT_TYPE_CGN_SIGNAL: + if (phba->cmf_active_mode == LPFC_CFG_OFF) + break; + cgn_signal = (struct lpfc_acqe_cgn_signal *) + &acqe_sli->event_data1; + phba->cgn_acqe_cnt++; + + cnt = bf_get(lpfc_warn_acqe, cgn_signal); + + /* no threshold for CMF, even 1 signal will trigger an event */ + + /* Alarm overrides warning, so check that first */ + if (cgn_signal->alarm_cnt) { + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + /* Keep track of alarm cnt for cgn_info */ + atomic_add(cgn_signal->alarm_cnt, + &phba->cgn_fabric_alarm_cnt); + /* Keep track of alarm cnt for CMF_SYNC_WQE */ + atomic_add(cgn_signal->alarm_cnt, + &phba->cgn_sync_alarm_cnt); + } + } else if (cnt) { + /* signal action needs to be taken */ + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + /* Keep track of warning cnt for cgn_info */ + atomic_add(cnt, &phba->cgn_fabric_warn_cnt); + /* Keep track of warning cnt for CMF_SYNC_WQE */ + atomic_add(cnt, &phba->cgn_sync_warn_cnt); + } + } + break; default: lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3193 Async SLI event - Event Data1:x%08x Event Data2:" - "x%08x SLI Event Type:%d\n", - acqe_sli->event_data1, acqe_sli->event_data2, + "3193 Unrecognized SLI event, type: 0x%x", evt_type); break; } @@ -5554,8 +6624,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, case LPFC_FIP_EVENT_TYPE_NEW_FCF: case LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD: if (event_type == LPFC_FIP_EVENT_TYPE_NEW_FCF) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2546 New FCF event, evt_tag:x%x, " "index:x%x\n", acqe_fip->event_tag, @@ -5608,23 +6677,24 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2547 Issue FCF scan read FCF mailbox " "command failed (x%x)\n", rc); break; case LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2548 FCF Table full count 0x%x tag 0x%x\n", - bf_get(lpfc_acqe_fip_fcf_count, acqe_fip), - acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2548 FCF Table full count 0x%x tag 0x%x\n", + bf_get(lpfc_acqe_fip_fcf_count, acqe_fip), + acqe_fip->event_tag); break; case LPFC_FIP_EVENT_TYPE_FCF_DEAD: phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2549 FCF (x%x) disconnected from network, " - "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2549 FCF (x%x) disconnected from network, " + "tag:x%x\n", acqe_fip->index, + acqe_fip->event_tag); /* * If we are in the middle of FCF failover process, clear * the corresponding FCF bit in the roundrobin bitmap. @@ -5661,8 +6731,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_redisc_fcf_table(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, - "2772 Issue FCF rediscover mailbox " + LOG_TRACE_EVENT, + "2772 Issue FCF rediscover mabilbox " "command failed, fail through to FCF " "dead event\n"); spin_lock_irq(&phba->hbalock); @@ -5685,7 +6755,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, break; case LPFC_FIP_EVENT_TYPE_CVL: phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2718 Clear Virtual Link Received for VPI 0x%x" " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag); @@ -5752,9 +6823,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_redisc_fcf_table(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, + LOG_TRACE_EVENT, "2774 Issue FCF rediscover " - "mailbox command failed, " + "mabilbox command failed, " "through to CVL event\n"); spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_ACVL_DISC; @@ -5773,9 +6844,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, } break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0288 Unknown FCoE event type 0x%x event tag " - "0x%x\n", event_type, acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0288 Unknown FCoE event type 0x%x event tag " + "0x%x\n", event_type, acqe_fip->event_tag); break; } } @@ -5792,7 +6863,7 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, struct lpfc_acqe_dcbx *acqe_dcbx) { phba->fc_eventTag = acqe_dcbx->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0290 The SLI4 DCBX asynchronous event is not " "handled yet\n"); } @@ -5823,6 +6894,326 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, phba->sli4_hba.link_state.logical_speed); } +/** + * lpfc_sli4_async_cmstat_evt - Process the asynchronous cmstat event + * @phba: pointer to lpfc hba data structure. + * + * This routine is to handle the SLI4 asynchronous cmstat event. A cmstat event + * is an asynchronous notification of a request to reset CM stats. + **/ +static void +lpfc_sli4_async_cmstat_evt(struct lpfc_hba *phba) +{ + if (!phba->cgn_i) + return; + lpfc_init_congestion_stat(phba); +} + +/** + * lpfc_cgn_params_val - Validate FW congestion parameters. + * @phba: pointer to lpfc hba data structure. + * @p_cfg_param: pointer to FW provided congestion parameters. + * + * This routine validates the 8 congestion parameters passed + * by the FW to the driver via an ACQE event. The parameters + * are checked for in-range values. Any value out of range + * is set back to its default. + * + **/ +static void +lpfc_cgn_params_val(struct lpfc_hba *phba, struct lpfc_cgn_param *p_cfg_param) +{ + spin_lock_irq(&phba->hbalock); + if (!lpfc_rangecheck(p_cfg_param->cgn_param_mode, LPFC_CFG_OFF, + LPFC_CFG_MONITOR)) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6225 CMF mode param out of range: %d\n", + p_cfg_param->cgn_param_mode); + p_cfg_param->cgn_param_mode = LPFC_CFG_OFF; + } + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr, LPFC_CFG_CONSERVE, + LPFC_CFG_SEVERE)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6226 CMF ACR param out of range: %d\n", + p_cfg_param->cgn_param_acr); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_rxburst, + LPFC_CFG_BURST_MIN, LPFC_CFG_BURST_MAX)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6227 CMF rxburst param out of range: %d\n", + p_cfg_param->cgn_param_rxburst); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_rxbw, + LPFC_CFG_BW_MIN, LPFC_CFG_BW_MAX)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6228 CMF rxbw param out of range: %d\n", + p_cfg_param->cgn_param_rxbw); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr_max_rxburst, + LPFC_CFG_BURST_MIN, LPFC_CFG_BURST_MAX)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6229 CMF maxACRburst param out of range: %d\n", + p_cfg_param->cgn_param_acr_max_rxburst); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr_max_rxbw, + LPFC_CFG_BW_MIN, LPFC_CFG_BW_MAX)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6230 CMF maxACRbw param out of range: %d\n", + p_cfg_param->cgn_param_acr_max_rxbw); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr_scale, + LPFC_CFG_LOW_SCALE, LPFC_CFG_HIGH_SCALE)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6231 CMF ACRscale param out of range: %d\n", + p_cfg_param->cgn_param_acr_scale); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr_min_rxburst, 1, + p_cfg_param->cgn_param_acr_max_rxburst)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6232 CMF minACRburst param out of range: %d\n", + p_cfg_param->cgn_param_acr_min_rxburst); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_acr_min_rxbw, + LPFC_CFG_BW_MIN, + p_cfg_param->cgn_param_acr_max_rxbw)) + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6233 CMF minACRbw param out of range: %d\n", + p_cfg_param->cgn_param_acr_min_rxbw); + spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_congparm_chg_evt - Process a FW cong parm Change event + * @phba: pointer to lpfc hba data structure. + * @p_cgn_params: pointer to a data buffer with the FW cong params. + * @len: the size of pdata in bytes. + * + * This routine validates the congestion management buffer signature + * from the FW, validates the contents and makes corrections for + * valid, in-range values. If the signature magic is correct and + * after parameter validation, the contents are copied to the driver's + * @phba structure. If the magic is incorrect, an error message is + * logged. + **/ +static void +lpfc_cgn_params_parse(struct lpfc_hba *phba, + struct lpfc_cgn_param *p_cgn_param, uint32_t len) +{ + struct lpfc_cgn_info *cp; + uint32_t crc, oldmode; + + /* Make sure the FW has encoded the correct magic number to + * validate the congestion parameter in FW memory. + */ + if (p_cgn_param->cgn_param_magic == LPFC_CFG_PARAM_MAGIC_NUM) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "4668 FW cgn parm buffer data: " + "magic 0x%x version %d mode %d " + "acr %d rx_burst_sz %d " + "rx_bw_rate_max %d acr_burst_rate_max %d " + "acr_bw_rate %d acr_burst_rate_min %d " + "acr_bw_min %d scale %d activeMode %d\n", + p_cgn_param->cgn_param_magic, + p_cgn_param->cgn_param_version, + p_cgn_param->cgn_param_mode, + p_cgn_param->cgn_param_acr, + p_cgn_param->cgn_param_rxburst, + p_cgn_param->cgn_param_rxbw, + p_cgn_param->cgn_param_acr_max_rxburst, + p_cgn_param->cgn_param_acr_max_rxbw, + p_cgn_param->cgn_param_acr_min_rxburst, + p_cgn_param->cgn_param_acr_min_rxbw, + p_cgn_param->cgn_param_acr_scale, + phba->cmf_active_mode); + + oldmode = phba->cmf_active_mode; + + /* Any parameters out of range are corrected to defaults + * by this routine. No need to fail. + */ + lpfc_cgn_params_val(phba, p_cgn_param); + + /* Parameters are verified, move them into driver storage */ + spin_lock_irq(&phba->hbalock); + memcpy(&phba->cgn_p, p_cgn_param, + sizeof(struct lpfc_cgn_param)); + + /* Update parameters in congestion info buffer now */ + if (phba->cgn_i) { + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_acr = phba->cgn_p.cgn_param_acr; + cp->cgn_info_rxburst = phba->cgn_p.cgn_param_rxburst; + cp->cgn_info_rxbw = phba->cgn_p.cgn_param_rxbw; + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + } + spin_unlock_irq(&phba->hbalock); + + phba->cmf_active_mode = phba->cgn_p.cgn_param_mode; + + switch (oldmode) { + case LPFC_CFG_OFF: + if (phba->cgn_p.cgn_param_mode != LPFC_CFG_OFF) { + /* Turning CMF on */ + lpfc_cmf_start(phba); + + if (phba->link_state >= LPFC_LINK_UP) { + phba->cgn_reg_fpin = + phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = + phba->cgn_init_reg_signal; + lpfc_issue_els_edc(phba->pport, 0); + } + } + break; + case LPFC_CFG_MANAGED: + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + /* Turning CMF off */ + lpfc_cmf_stop(phba); + if (phba->link_state >= LPFC_LINK_UP) + lpfc_issue_els_edc(phba->pport, 0); + break; + case LPFC_CFG_MONITOR: + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4661 Switch from MANAGED to " + "`MONITOR mode\n"); + phba->cmf_max_bytes_per_interval = + phba->cmf_link_byte_count; + + /* Resume blocked IO - unblock on workqueue */ + queue_work(phba->wq, + &phba->unblock_request_work); + break; + } + break; + case LPFC_CFG_MONITOR: + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + /* Turning CMF off */ + lpfc_cmf_stop(phba); + if (phba->link_state >= LPFC_LINK_UP) + lpfc_issue_els_edc(phba->pport, 0); + break; + case LPFC_CFG_MANAGED: + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4662 Switch from MONITOR to " + "MANAGED mode\n"); + lpfc_cmf_signal_init(phba); + break; + } + break; + } + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4669 FW cgn parm buf wrong magic 0x%x " + "version %d\n", p_cgn_param->cgn_param_magic, + p_cgn_param->cgn_param_version); + } +} + +/** + * lpfc_sli4_cgn_params_read - Read and Validate FW congestion parameters. + * @phba: pointer to lpfc hba data structure. + * + * This routine issues a read_object mailbox command to + * get the congestion management parameters from the FW + * parses it and updates the driver maintained values. + * + * Returns + * 0 if the object was empty + * -Eval if an error was encountered + * Count if bytes were read from object + **/ +int +lpfc_sli4_cgn_params_read(struct lpfc_hba *phba) +{ + int ret = 0; + struct lpfc_cgn_param *p_cgn_param = NULL; + u32 *pdata = NULL; + u32 len = 0; + + /* Find out if the FW has a new set of congestion parameters. */ + len = sizeof(struct lpfc_cgn_param); + pdata = kzalloc(len, GFP_KERNEL); + ret = lpfc_read_object(phba, (char *)LPFC_PORT_CFG_NAME, + pdata, len); + + /* 0 means no data. A negative means error. A positive means + * bytes were copied. + */ + if (!ret) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4670 CGN RD OBJ returns no data\n"); + goto rd_obj_err; + } else if (ret < 0) { + /* Some error. Just exit and return it to the caller.*/ + goto rd_obj_err; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "6234 READ CGN PARAMS Successful %d\n", len); + + /* Parse data pointer over len and update the phba congestion + * parameters with values passed back. The receive rate values + * may have been altered in FW, but take no action here. + */ + p_cgn_param = (struct lpfc_cgn_param *)pdata; + lpfc_cgn_params_parse(phba, p_cgn_param, len); + + rd_obj_err: + kfree(pdata); + return ret; +} + +/** + * lpfc_sli4_cgn_parm_chg_evt - Process a FW congestion param change event + * @phba: pointer to lpfc hba data structure. + * + * The FW generated Async ACQE SLI event calls this routine when + * the event type is an SLI Internal Port Event and the Event Code + * indicates a change to the FW maintained congestion parameters. + * + * This routine executes a Read_Object mailbox call to obtain the + * current congestion parameters maintained in FW and corrects + * the driver's active congestion parameters. + * + * The acqe event is not passed because there is no further data + * required. + * + * Returns nonzero error if event processing encountered an error. + * Zero otherwise for success. + **/ +static int +lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *phba) +{ + int ret = 0; + + if (!phba->sli4_hba.pc_sli4_params.cmf) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4664 Cgn Evt when E2E off. Drop event\n"); + return -EACCES; + } + + /* If the event is claiming an empty object, it's ok. A write + * could have cleared it. Only error is a negative return + * status. + */ + ret = lpfc_sli4_cgn_params_read(phba); + if (ret < 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4667 Error reading Cgn Params (%d)\n", + ret); + } else if (!ret) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4673 CGN Event empty object.\n"); + } + return ret; +} + /** * lpfc_sli4_async_event_proc - Process all the pending asynchronous event * @phba: pointer to lpfc hba data structure. @@ -5833,18 +7224,21 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the async event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ASYNC_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the async events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_asynce_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, + iflags); + /* Process the asynchronous event */ switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) { case LPFC_TRAILER_CODE_LINK: @@ -5868,16 +7262,23 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) case LPFC_TRAILER_CODE_SLI: lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli); break; + case LPFC_TRAILER_CODE_CMSTAT: + lpfc_sli4_async_cmstat_evt(phba); + break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "1804 Invalid asynchrous event code: " "x%x\n", bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)); break; } + /* Free the completion event processed to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); } /** @@ -5905,7 +7306,7 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba) "2777 Start post-quiescent FCF table scan\n"); rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2747 Issue FCF scan read FCF mailbox " "command failed 0x%x\n", rc); } @@ -5976,7 +7377,7 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) "0480 Enabled MSI-X interrupt mode.\n"); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0482 Illegal interrupt mode.\n"); break; } @@ -5998,17 +7399,20 @@ static int lpfc_enable_pci_dev(struct lpfc_hba *phba) { struct pci_dev *pdev; + int bars = 0; /* Obtain PCI device reference */ if (!phba->pcidev) goto out_error; else pdev = phba->pcidev; + /* Select PCI BARs */ + bars = pci_select_bars(pdev, IORESOURCE_MEM); /* Enable PCI device */ if (pci_enable_device_mem(pdev)) goto out_error; /* Request PCI resource for the device */ - if (pci_request_mem_regions(pdev, LPFC_DRIVER_NAME)) + if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) goto out_disable_device; /* Set up device as PCI master and save state for EEH */ pci_set_master(pdev); @@ -6016,7 +7420,7 @@ lpfc_enable_pci_dev(struct lpfc_hba *phba) pci_save_state(pdev); /* PCIe EEH recovery on powerpc platforms needs fundamental reset */ - if (pci_is_pcie(pdev)) + if (pci_find_capability(pdev, PCI_CAP_ID_EXP)) pdev->needs_freset = 1; return 0; @@ -6024,8 +7428,8 @@ lpfc_enable_pci_dev(struct lpfc_hba *phba) out_disable_device: pci_disable_device(pdev); out_error: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1401 Failed to enable pci device\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "1401 Failed to enable pci device, bars:x%x\n", bars); return -ENODEV; } @@ -6040,15 +7444,20 @@ static void lpfc_disable_pci_dev(struct lpfc_hba *phba) { struct pci_dev *pdev; + int bars; /* Obtain PCI device reference */ if (!phba->pcidev) return; else pdev = phba->pcidev; + /* Select PCI BARs */ + bars = pci_select_bars(pdev, IORESOURCE_MEM); /* Release PCI resource and disable PCI device */ - pci_release_mem_regions(pdev); + pci_release_selected_regions(pdev, bars); pci_disable_device(pdev); + /* Null out PCI private reference to driver */ + pci_set_drvdata(pdev, NULL); return; } @@ -6070,10 +7479,14 @@ lpfc_reset_hba(struct lpfc_hba *phba) phba->link_state = LPFC_HBA_ERROR; return; } - if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + + /* If not LPFC_SLI_ACTIVE, force all IO to be flushed */ + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) { lpfc_offline_prep(phba, LPFC_MBX_WAIT); - else + } else { lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); + lpfc_sli_flush_io_rings(phba); + } lpfc_offline(phba); lpfc_sli_brdrestart(phba); lpfc_online(phba); @@ -6125,7 +7538,7 @@ lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba); if (nr_vfn > max_nr_vfn) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3057 Requested vfs (%d) greater than " "supported vfs (%d)", nr_vfn, max_nr_vfn); return -EINVAL; @@ -6144,6 +7557,15 @@ lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) return rc; } +static void +lpfc_unblock_requests_work(struct work_struct *work) +{ + struct lpfc_hba *phba = container_of(work, struct lpfc_hba, + unblock_request_work); + + lpfc_unblock_requests(phba); +} + /** * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources. * @phba: pointer to lpfc hba data structure. @@ -6164,6 +7586,9 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) * Driver resources common to all SLI revisions */ atomic_set(&phba->fast_event_count, 0); + atomic_set(&phba->dbg_log_idx, 0); + atomic_set(&phba->dbg_log_cnt, 0); + atomic_set(&phba->dbg_log_dmping, 0); spin_lock_init(&phba->hbalock); /* Initialize ndlp management spinlock */ @@ -6206,6 +7631,18 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) spin_lock_init(&phba->devicelock); INIT_LIST_HEAD(&phba->luns); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + /* MBOX heartbeat timer */ + setup_timer(&psli->mbox_tmo, lpfc_mbox_timeout, (unsigned long)phba); + /* Fabric block timer */ + setup_timer(&phba->fabric_block_timer, lpfc_fabric_block_timeout, + (unsigned long)phba); + /* EA polling mode timer */ + setup_timer(&phba->eratt_poll, lpfc_poll_eratt, + (unsigned long)phba); + /* Heartbeat timer */ + setup_timer(&phba->hb_tmofunc, lpfc_hb_timeout, (unsigned long)phba); +#else /* MBOX heartbeat timer */ timer_setup(&psli->mbox_tmo, lpfc_mbox_timeout, 0); /* Fabric block timer */ @@ -6214,9 +7651,11 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) timer_setup(&phba->eratt_poll, lpfc_poll_eratt, 0); /* Heartbeat timer */ timer_setup(&phba->hb_tmofunc, lpfc_hb_timeout, 0); - +#endif INIT_DELAYED_WORK(&phba->eq_delay_work, lpfc_hb_eq_delay_work); - + INIT_DELAYED_WORK(&phba->idle_stat_delay_work, + lpfc_idle_stat_delay_work); + INIT_WORK(&phba->unblock_request_work, lpfc_unblock_requests_work); return 0; } @@ -6241,7 +7680,12 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) */ /* FCP polling mode timer */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&phba->fcp_poll_timer, lpfc_poll_timeout, + (unsigned long)phba); +#else timer_setup(&phba->fcp_poll_timer, lpfc_poll_timeout, 0); +#endif /* Host attention work mask setup */ phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); @@ -6263,9 +7707,8 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } if (!phba->sli.sli3_ring) - phba->sli.sli3_ring = kcalloc(LPFC_SLI3_MAX_RING, - sizeof(struct lpfc_sli_ring), - GFP_KERNEL); + phba->sli.sli3_ring = kzalloc(LPFC_SLI3_MAX_RING * + sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (!phba->sli.sli3_ring) return -ENOMEM; @@ -6274,18 +7717,16 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) * used to create the sg_dma_buf_pool must be dynamically calculated. */ - /* Initialize the host templates the configured values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; - if (phba->sli_rev == LPFC_SLI_REV4) entry_sz = sizeof(struct sli4_sge); else entry_sz = sizeof(struct ulp_bde64); + atomic_set(&phba->rxtable_idx_head, 0); + atomic_set(&phba->rxtable_idx_tail, 0); + /* There are going to be 2 reserved BDEs: 1 FCP cmnd + 1 FCP rsp */ - if (phba->cfg_enable_bg) { + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { /* * The scsi_buf for a T10-DIF I/O will hold the FCP cmnd, * the FCP rsp, and a BDE for each. Sice we have no control @@ -6319,7 +7760,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, - "9088 sg_tablesize:%d dmabuf_size:%d total_bde:%d\n", + "9088 INIT sg_tablesize:%d dmabuf_size:%d total_bde:%d\n", phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt); @@ -6413,16 +7854,20 @@ static int lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; - MAILBOX_t *mb; int rc, i, max_buf_size; + uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0}; + struct lpfc_mqe *mqe; int longs; int extra; +#ifdef BUILD_NVME + MAILBOX_t *mb; uint64_t wwn; +#endif u32 if_type; u32 if_fam; phba->sli4_hba.num_present_cpu = lpfc_present_cpu; - phba->sli4_hba.num_possible_cpu = num_possible_cpus(); + phba->sli4_hba.num_possible_cpu = cpumask_last(cpu_possible_mask) + 1; phba->sli4_hba.curr_disp_cpu = 0; /* Get all the module params for configuring this host */ @@ -6442,15 +7887,32 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* The lpfc_wq workqueue for deferred irq use */ phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); +#if defined(BUILD_NVME) + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + phba->nvme_io = alloc_workqueue("lpfc_nvme_io", + WQ_MEM_RECLAIM, 0); +#endif /* * Initialize timers used by driver */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&phba->rrq_tmr, lpfc_rrq_timeout, (unsigned long)phba); + /* FCF rediscover timer */ + setup_timer(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo, + (unsigned long)phba); + +#else timer_setup(&phba->rrq_tmr, lpfc_rrq_timeout, 0); /* FCF rediscover timer */ timer_setup(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo, 0); +#endif + + /* CMF congestion timer */ + hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + phba->cmf_timer.function = lpfc_cmf_timer; /* * Control structure for handling external multi-buffer mailbox @@ -6501,6 +7963,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* This abort list used by worker thread */ spin_lock_init(&phba->sli4_hba.sgl_list_lock); spin_lock_init(&phba->sli4_hba.nvmet_io_wait_lock); + spin_lock_init(&phba->sli4_hba.asynce_list_lock); + spin_lock_init(&phba->sli4_hba.els_xri_abrt_list_lock); /* * Initialize driver internal slow-path work queues @@ -6512,8 +7976,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); /* Asynchronous event CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); - /* Fast-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue); /* Slow-path XRI aborted CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Receive queue CQ Event work queue list */ @@ -6525,6 +7987,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list); INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list); + /* Initialise active auth configuration list */ + INIT_LIST_HEAD(&phba->lpfc_auth_active_cfg_list); + /* Initialize mboxq lists. If the early init routines fail * these lists need to be correctly initialized. */ @@ -6584,6 +8049,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) } /* Check for NVMET being configured */ +#if defined(BUILD_NVME) phba->nvmet_support = 0; if (lpfc_enable_nvmet_cnt) { @@ -6591,7 +8057,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) lpfc_read_nv(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6016 Mailbox failed , mbxCmd x%x " "READ_NV, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &mboxq->u.mqe), @@ -6610,7 +8077,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* wwn is WWPN of HBA instance */ wwn = cpu_to_be64(wwn); phba->sli4_hba.wwpn.u.name = wwn; - /* Check to see if it matches any module parameter */ for (i = 0; i < lpfc_enable_nvmet_cnt; i++) { if (wwn == lpfc_enable_nvmet[i]) { @@ -6620,24 +8086,60 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->nvmet_support = 1; /* a match */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6017 NVME Target %016llx\n", wwn); #else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6021 Can't enable NVME Target." " NVME_TARGET_FC infrastructure" " is not in kernel\n"); #endif /* Not supported for NVMET */ phba->cfg_xri_rebalancing = 0; + if (phba->irq_chann_mode == NHT_MODE) { + phba->cfg_irq_chann = + phba->sli4_hba.num_present_cpu; + phba->cfg_hdw_queue = + phba->sli4_hba.num_present_cpu; + phba->irq_chann_mode = NORMAL_MODE; + } break; } } } +#endif lpfc_nvme_mod_param_dep(phba); + /* Get the Supported Pages if PORT_CAPABILITIES is supported by port. */ + lpfc_supported_pages(mboxq); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (!rc) { + mqe = &mboxq->u.mqe; + memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), + LPFC_MAX_SUPPORTED_PAGES); + for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { + switch (pn_page[i]) { + case LPFC_SLI4_PARAMETERS: + phba->sli4_hba.pc_sli4_params.supported = 1; + break; + default: + break; + } + } + /* Read the port's SLI4 Parameters capabilities if supported. */ + if (phba->sli4_hba.pc_sli4_params.supported) + rc = lpfc_pc_sli4_params_get(phba, mboxq); + if (rc) { + mempool_free(mboxq, phba->mbox_mem_pool); + rc = -EIO; + goto out_free_bsmbx; + } + } + /* * Get sli4 parameters that override parameters from Port capabilities. * If this call fails, it isn't critical unless the SLI4 parameters come @@ -6651,20 +8153,18 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) &phba->sli4_hba.sli_intf); if (phba->sli4_hba.extents_in_use && phba->sli4_hba.rpi_hdrs_in_use) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2999 Unsupported SLI4 Parameters " - "Extents and RPI headers enabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2999 Unsupported SLI4 Parameters " + "Extents and RPI headers enabled.\n"); if (if_type == LPFC_SLI_INTF_IF_TYPE_0 && if_fam == LPFC_SLI_INTF_FAMILY_BE2) { mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; goto out_free_bsmbx; } } if (!(if_type == LPFC_SLI_INTF_IF_TYPE_0 && if_fam == LPFC_SLI_INTF_FAMILY_BE2)) { mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; goto out_free_bsmbx; } } @@ -6706,16 +8206,30 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Total SGEs for scsi_sg_list and scsi_sg_prot_list */ phba->cfg_total_seg_cnt = LPFC_MAX_SGL_SEG_CNT; - /* - * If supporting DIF, reduce the seg count for scsi to - * allow room for the DIF sges. - */ - if (phba->cfg_enable_bg && - phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF) - phba->cfg_scsi_seg_cnt = LPFC_MAX_BG_SLI4_SEG_CNT_DIF; - else - phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; - + if (phba->cfg_enable_bg) { + /* + * Advertise to SCSI Layer less s/g support then + * we configure due to DIF setup overhead. + */ + if (phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF) + phba->cfg_scsi_seg_cnt = + LPFC_MAX_BG_SLI4_SEG_CNT_DIF; + else + phba->cfg_scsi_seg_cnt = + phba->cfg_sg_seg_cnt; + } else { + /* + * If just External DIF is enabled, there is + * no protection data to deal with, so we have less + * SGE overhead in the SGL. + */ + if (phba->cfg_sg_seg_cnt > LPFC_MAX_ED_SLI4_SEG_CNT_DIF) + phba->cfg_scsi_seg_cnt = + LPFC_MAX_ED_SLI4_SEG_CNT_DIF; + else + phba->cfg_scsi_seg_cnt = + phba->cfg_sg_seg_cnt; + } } else { /* * The scsi_buf for a regular I/O holds the FCP cmnd, @@ -6748,6 +8262,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->border_sge_num = phba->cfg_sg_dma_buf_size / sizeof(struct sli4_sge); +#if defined(BUILD_NVME) /* Limit to LPFC_MAX_NVME_SEG_CNT for NVME. */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { @@ -6759,11 +8274,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) } else phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; } - - /* Initialize the host templates with the updated values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt; +#endif lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, "9087 sg_seg_cnt:%d dmabuf_size:%d " @@ -6818,23 +8329,23 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate and initialize active sgl array */ rc = lpfc_init_active_sgl_array(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1430 Failed to initialize sgl list.\n"); goto out_destroy_cq_event_pool; } rc = lpfc_sli4_init_rpi_hdrs(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1432 Failed to initialize rpi headers.\n"); goto out_free_active_sgl; } /* Allocate eligible FCF bmask memory for FCF roundrobin failover */ longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG; - phba->fcf.fcf_rr_bmask = kcalloc(longs, sizeof(unsigned long), + phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (!phba->fcf.fcf_rr_bmask) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2759 Failed allocate memory for FCF round " "robin failover bmask\n"); rc = -ENOMEM; @@ -6845,7 +8356,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sizeof(struct lpfc_hba_eq_hdl), GFP_KERNEL); if (!phba->sli4_hba.hba_eq_hdl) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2572 Failed allocate memory for " "fast-path per-EQ handle array\n"); rc = -ENOMEM; @@ -6856,7 +8367,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sizeof(struct lpfc_vector_map_info), GFP_KERNEL); if (!phba->sli4_hba.cpu_map) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3327 Failed allocate memory for msi-x " "interrupt vector mapping\n"); rc = -ENOMEM; @@ -6865,11 +8376,39 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->sli4_hba.eq_info = alloc_percpu(struct lpfc_eq_intr_info); if (!phba->sli4_hba.eq_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3321 Failed allocation for per_cpu stats\n"); rc = -ENOMEM; goto out_free_hba_cpu_map; } + + phba->sli4_hba.idle_stat = kcalloc(phba->sli4_hba.num_possible_cpu, + sizeof(*phba->sli4_hba.idle_stat), + GFP_KERNEL); + if (!phba->sli4_hba.idle_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3390 Failed allocation for idle_stat\n"); + rc = -ENOMEM; + goto out_free_hba_eq_info; + } + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + phba->sli4_hba.c_stat = alloc_percpu(struct lpfc_hdwq_stat); + if (!phba->sli4_hba.c_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3332 Failed allocating per cpu hdwq stats\n"); + rc = -ENOMEM; + goto out_free_hba_idle_stat; + } +#endif + + phba->cmf_stat = alloc_percpu(struct lpfc_cgn_stat); + if (!phba->cmf_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3331 Failed allocating per cpu cgn stats\n"); + rc = -ENOMEM; + goto out_free_hba_hdwq_info; + } /* * Enable sr-iov virtual functions if supported and configured * through the module parameter. @@ -6889,6 +8428,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) return 0; +out_free_hba_hdwq_info: + free_percpu(phba->sli4_hba.c_stat); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +out_free_hba_idle_stat: + kfree(phba->sli4_hba.idle_stat); +#endif +out_free_hba_eq_info: + free_percpu(phba->sli4_hba.eq_info); out_free_hba_cpu_map: kfree(phba->sli4_hba.cpu_map); out_free_hba_eq_hdl: @@ -6927,12 +8474,18 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; free_percpu(phba->sli4_hba.eq_info); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + free_percpu(phba->sli4_hba.c_stat); +#endif + free_percpu(phba->cmf_stat); + kfree(phba->sli4_hba.idle_stat); /* Free memory allocated for msi-x interrupt vector to CPU mapping */ kfree(phba->sli4_hba.cpu_map); phba->sli4_hba.num_possible_cpu = 0; phba->sli4_hba.num_present_cpu = 0; phba->sli4_hba.curr_disp_cpu = 0; + cpumask_clear(&phba->sli4_hba.irq_aff_mask); /* Free memory allocated for fast-path work queue handles */ kfree(phba->sli4_hba.hba_eq_hdl); @@ -6968,7 +8521,6 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) list_del_init(&conn_entry->list); kfree(conn_entry); } - return; } @@ -7000,7 +8552,7 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->lpfc_stop_port = lpfc_stop_port_s4; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1431 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; @@ -7032,7 +8584,6 @@ lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba) error = PTR_ERR(phba->worker_thread); return error; } - return 0; } @@ -7053,6 +8604,13 @@ lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba) phba->wq = NULL; } +#if defined(BUILD_NVME) + if (phba->nvme_io) { + flush_workqueue(phba->nvme_io); + destroy_workqueue(phba->nvme_io); + phba->nvme_io = NULL; + } +#endif /* Stop kernel worker thread */ if (phba->worker_thread) kthread_stop(phba->worker_thread); @@ -7106,7 +8664,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) if (iocbq_entry == NULL) { printk(KERN_ERR "%s: only allocated %d iocbs of " "expected %d count. Unloading driver.\n", - __func__, i, LPFC_IOCB_LIST_CNT); + __func__, i, iocb_count); goto out_free_iocbq; } @@ -7295,7 +8853,7 @@ lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0391 Error during rpi post operation\n"); lpfc_sli4_remove_rpis(phba); rc = -ENODEV; @@ -7523,21 +9081,15 @@ lpfc_create_shost(struct lpfc_hba *phba) shost = lpfc_shost_from_vport(vport); phba->pport = vport; +#if defined(BUILD_NVME) if (phba->nvmet_support) { /* Only 1 vport (pport) will support NVME target */ - if (phba->txrdy_payload_pool == NULL) { - phba->txrdy_payload_pool = dma_pool_create( - "txrdy_pool", &phba->pcidev->dev, - TXRDY_PAYLOAD_LEN, 16, 0); - if (phba->txrdy_payload_pool) { - phba->targetport = NULL; - phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME; - lpfc_printf_log(phba, KERN_INFO, - LOG_INIT | LOG_NVME_DISC, - "6076 NVME Target Found\n"); - } - } + phba->targetport = NULL; + phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME_DISC, + "6076 NVME Target Found\n"); } +#endif lpfc_debugfs_initialize(vport); /* Put reference to SCSI host to driver's device private data */ @@ -7615,7 +9167,7 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) if (phba->cfg_prot_mask && phba->cfg_prot_guard) { if ((old_mask != phba->cfg_prot_mask) || (old_guard != phba->cfg_prot_guard)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1475 Registering BlockGuard with the " "SCSI layer: mask %d guard %d\n", phba->cfg_prot_mask, @@ -7624,7 +9176,7 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) scsi_host_set_prot(shost, phba->cfg_prot_mask); scsi_host_set_guard(shost, phba->cfg_prot_guard); } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1479 Not Registering BlockGuard with the SCSI " "layer, Bad protection parameters: %d %d\n", old_mask, old_guard); @@ -7719,7 +9271,7 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) if (!phba->slim_memmap_p) { dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLIM memory.\n"); - goto out; + return error; } /* Map HBA Control Registers to a kernel virtual address. */ @@ -7778,7 +9330,7 @@ out_iounmap: iounmap(phba->ctrl_regs_memmap_p); out_iounmap_slim: iounmap(phba->slim_memmap_p); -out: + return error; } @@ -7855,7 +9407,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) * other register reads as the data may not be valid. Just exit. */ if (port_error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1408 Port Failed POST - portsmphr=0x%x, " "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, " "scr2=x%x, hscratch=x%x, pstatus=x%x\n", @@ -7904,7 +9456,8 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "1422 Unrecoverable Error " "Detected during POST " "uerr_lo_reg=0x%x, " @@ -7931,7 +9484,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) phba->work_status[1] = readl(phba->sli4_hba.u.if_type2. ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2888 Unrecoverable port error " "following POST: port status reg " "0x%x, port_smphr reg 0x%x, " @@ -8034,7 +9587,7 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) break; case LPFC_SLI_INTF_IF_TYPE_1: default: - dev_printk(KERN_ERR, &phba->pcidev->dev, + dev_err(&phba->pcidev->dev, "FATAL - unsupported SLI4 interface type - %d\n", if_type); break; @@ -8052,8 +9605,7 @@ lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba, uint32_t if_type) { switch (if_type) { case LPFC_SLI_INTF_IF_TYPE_0: - phba->sli4_hba.PSMPHRregaddr = - phba->sli4_hba.ctrl_regs_memmap_p + + phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + LPFC_SLIPORT_IF0_SMPHR; phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + LPFC_HST_ISR0; @@ -8077,7 +9629,7 @@ lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba, uint32_t if_type) case LPFC_SLI_INTF_IF_TYPE_2: case LPFC_SLI_INTF_IF_TYPE_1: default: - dev_err(&phba->pcidev->dev, + dev_printk(KERN_ERR, &phba->pcidev->dev, "FATAL - unsupported SLI4 interface type - %d\n", if_type); break; @@ -8215,6 +9767,86 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx)); } +static const char * const lpfc_topo_to_str[] = { + "Loop then P2P", + "Loopback", + "P2P Only", + "Unsupported", + "Loop Only", + "Unsupported", + "P2P then Loop", +}; + +/** + * lpfc_map_topology - Map the topology read from READ_CONFIG + * @phba: pointer to lpfc hba data structure. + * @rdconf: pointer to read config data + * + * This routine is invoked to map the topology values as read + * from the read config mailbox command. If the persistent + * topology feature is supported, the firmware will provide the + * saved topology information to be used in INIT_LINK + * + **/ +#define LINK_FLAGS_DEF 0x0 +#define LINK_FLAGS_P2P 0x1 +#define LINK_FLAGS_LOOP 0x2 +static void +lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) +{ + u8 ptv, tf, pt; + + ptv = bf_get(lpfc_mbx_rd_conf_ptv, rd_config); + tf = bf_get(lpfc_mbx_rd_conf_tf, rd_config); + pt = bf_get(lpfc_mbx_rd_conf_pt, rd_config); + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2027 Read Config Data : ptv:0x%x, tf:0x%x pt:0x%x", + ptv, tf, pt); + if (!ptv) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2019 FW does not support persistent topology " + "Using driver parameter defined value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + return; + } + /* FW supports persistent topology - override module parameter value */ + phba->hba_flag |= HBA_PERSISTENT_TOPO; + switch (phba->pcidev->device) { + case PCI_DEVICE_ID_LANCER_G7_FC: + case PCI_DEVICE_ID_LANCER_G6_FC: + if (!tf) { + phba->cfg_topology = ((pt == LINK_FLAGS_LOOP) + ? FLAGS_TOPOLOGY_MODE_LOOP + : FLAGS_TOPOLOGY_MODE_PT_PT); + } else { + phba->hba_flag &= ~HBA_PERSISTENT_TOPO; + } + break; + default: /* G5 */ + if (tf) { + /* If topology failover set - pt is '0' or '1' */ + phba->cfg_topology = (pt ? FLAGS_TOPOLOGY_MODE_PT_LOOP : + FLAGS_TOPOLOGY_MODE_LOOP_PT); + } else { + phba->cfg_topology = ((pt == LINK_FLAGS_P2P) + ? FLAGS_TOPOLOGY_MODE_PT_PT + : FLAGS_TOPOLOGY_MODE_LOOP); + } + break; + } + if (phba->hba_flag & HBA_PERSISTENT_TOPO) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2020 Using persistent topology value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2021 Invalid topology values from FW " + "Using driver parameter defined value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + } +} + /** * lpfc_sli4_read_config - Get the config parameters. * @phba: pointer to lpfc hba data structure. @@ -8245,7 +9877,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2011 Unable to allocate memory for issuing " "SLI_CONFIG_SPECIAL mailbox command\n"); return -ENOMEM; @@ -8255,11 +9887,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2012 Mailbox failed , mbxCmd x%x " - "READ_CONFIG, mbxStatus x%x\n", - bf_get(lpfc_mqe_command, &pmb->u.mqe), - bf_get(lpfc_mqe_status, &pmb->u.mqe)); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2012 Mailbox failed , mbxCmd x%x " + "READ_CONFIG, mbxStatus x%x\n", + bf_get(lpfc_mqe_command, &pmb->u.mqe), + bf_get(lpfc_mqe_status, &pmb->u.mqe)); rc = -EIO; } else { rd_config = &pmb->u.mqe.un.rd_config; @@ -8282,6 +9914,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->sli4_hba.bbscn_params.word0 = rd_config->word8; } + phba->sli4_hba.fawwpn_in_use = + bf_get(lpfc_mbx_rd_conf_fawwpn_inuse, rd_config); phba->sli4_hba.conf_trunk = bf_get(lpfc_mbx_rd_conf_trunk, rd_config); phba->sli4_hba.extents_in_use = @@ -8326,13 +9960,60 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + + /* Next decide on FPIN or Signal E2E CGN support + * For congestion alarms and warnings valid combination are: + * 1. FPIN alarms / FPIN warnings + * 2. Signal alarms / Signal warnings + * 3. FPIN alarms / Signal warnings + * 4. Signal alarms / FPIN warnings + * + * Initialize the adapter frequency to 100 mSecs + */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_BOTH; + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + + if (lpfc_use_cgn_signal) { + if (bf_get(lpfc_mbx_rd_conf_wcs, rd_config)) { + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_WARN; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + if (bf_get(lpfc_mbx_rd_conf_acs, rd_config)) { + /* MUST support both alarm and warning + * because EDC does not support alarm alone. + */ + if (phba->cgn_reg_signal != + LPFC_CGN_SIGNAL_WARN) { + /* Must support both or none */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_BOTH; + phba->cgn_reg_signal = + LPFC_CGN_SIGNAL_NO_SPT; + } else { + phba->cgn_reg_signal = + LPFC_CGN_SIGNAL_BOTH; + phba->cgn_reg_fpin = + LPFC_CGN_FPIN_NONE; + } + } + } + + /* Set the congestion initial signal and fpin values. */ + phba->cgn_init_reg_fpin = phba->cgn_reg_fpin; + phba->cgn_init_reg_signal = phba->cgn_reg_signal; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6446 READ_CONFIG reg_sig x%x reg_fpin:x%x\n", + phba->cgn_reg_signal, phba->cgn_reg_fpin); + + lpfc_map_topology(phba, rd_config); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2003 cfg params Extents? %d " "XRI(B:%d M:%d), " "VPI(B:%d M:%d) " "VFI(B:%d M:%d) " "RPI(B:%d M:%d) " - "FCFI:%d EQ:%d CQ:%d WQ:%d RQ:%d\n", + "FCFI:%d EQ:%d CQ:%d WQ:%d RQ:%d lmt:x%x\n", phba->sli4_hba.extents_in_use, phba->sli4_hba.max_cfg_param.xri_base, phba->sli4_hba.max_cfg_param.max_xri, @@ -8346,7 +10027,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->sli4_hba.max_cfg_param.max_eq, phba->sli4_hba.max_cfg_param.max_cq, phba->sli4_hba.max_cfg_param.max_wq, - phba->sli4_hba.max_cfg_param.max_rq); + phba->sli4_hba.max_cfg_param.max_rq, + phba->lmt); /* * Calculate queue resources based on how @@ -8368,8 +10050,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) /* Check to see if there is enough for NVME */ if ((phba->cfg_irq_chann > qmin) || (phba->cfg_hdw_queue > qmin)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2005 Reducing Queues: " + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "2005 Reducing Queues - " + "FW resource limitation: " "WQ %d CQ %d EQ %d: min %d: " "IRQ %d HDWQ %d\n", phba->sli4_hba.max_cfg_param.max_wq, @@ -8434,10 +10118,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) LPFC_USER_LINK_SPEED_AUTO; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0047 Unrecognized link " - "speed : %d\n", - forced_link_speed); + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "0047 Unrecognized link speed" + " : %d\n", forced_link_speed); phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; } @@ -8471,7 +10155,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (rc2 || shdr_status || shdr_add_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3026 Mailbox failed , mbxCmd x%x " "GET_FUNCTION_CONFIG, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &pmb->u.mqe), @@ -8508,7 +10192,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) "vf_number:%d\n", phba->sli4_hba.iov.pf_number, phba->sli4_hba.iov.vf_number); else - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3028 GET_FUNCTION_CONFIG: failed to find " "Resource Descriptor:x%x\n", LPFC_RSRC_DESC_TYPE_FCFCOE); @@ -8545,7 +10229,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0492 Unable to allocate memory for " "issuing SLI_CONFIG_SPECIAL mailbox " "command\n"); @@ -8560,7 +10244,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0493 SLI_CONFIG_SPECIAL mailbox " "failed with status x%x\n", rc); @@ -8599,8 +10283,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) */ if (phba->nvmet_support) { - if (phba->cfg_irq_chann < phba->cfg_nvmet_mrq) - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + if (phba->cfg_hdw_queue < phba->cfg_nvmet_mrq) + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; } @@ -8640,8 +10324,9 @@ lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0499 Failed allocate fast-path IO CQ (%d)\n", idx); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0499 Failed allocate fast-path IO CQ (%d)\n", + idx); return 1; } qdesc->qe_valid = 1; @@ -8663,7 +10348,7 @@ lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0503 Failed allocate fast-path IO WQ (%d)\n", idx); return 1; @@ -8719,7 +10404,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->cfg_hdw_queue, sizeof(struct lpfc_sli4_hdw_queue), GFP_KERNEL); if (!phba->sli4_hba.hdwq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6427 Failed allocate memory for " "fast-path Hardware Queue array\n"); goto out_error; @@ -8751,7 +10436,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_cqset) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3121 Fail allocate memory for " "fast-path CQ set array\n"); goto out_error; @@ -8761,7 +10446,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_mrq_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3122 Fail allocate memory for " "fast-path RQ set hdr array\n"); goto out_error; @@ -8771,7 +10456,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_mrq_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3124 Fail allocate memory for " "fast-path RQ set data array\n"); goto out_error; @@ -8799,7 +10484,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0497 Failed allocate EQ (%d)\n", cpup->hdwq); goto out_error; @@ -8842,7 +10527,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (lpfc_alloc_io_wq_cq(phba, idx)) goto out_error; } - if (phba->nvmet_support) { for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { cpu = lpfc_find_cpu_handle(phba, idx, @@ -8853,7 +10537,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3142 Failed allocate NVME " "CQ Set (%d)\n", idx); goto out_error; @@ -8875,7 +10559,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0500 Failed allocate slow-path mailbox CQ\n"); goto out_error; } @@ -8887,7 +10571,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0501 Failed allocate slow-path ELS CQ\n"); goto out_error; } @@ -8906,7 +10590,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.mq_esize, phba->sli4_hba.mq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0505 Failed allocate slow-path MQ\n"); goto out_error; } @@ -8922,7 +10606,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0504 Failed allocate slow-path ELS WQ\n"); goto out_error; } @@ -8936,7 +10620,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6079 Failed allocate NVME LS CQ\n"); goto out_error; } @@ -8949,7 +10633,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6080 Failed allocate NVME LS WQ\n"); goto out_error; } @@ -8967,7 +10651,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0506 Failed allocate receive HRQ\n"); goto out_error; } @@ -8978,7 +10662,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0507 Failed allocate receive DRQ\n"); goto out_error; } @@ -8996,7 +10680,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) LPFC_NVMET_RQE_DEF_COUNT, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3146 Failed allocate " "receive HRQ\n"); goto out_error; @@ -9009,7 +10693,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) GFP_KERNEL, cpu_to_node(cpu)); if (qdesc->rqbp == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6131 Failed allocate " "Header RQBP\n"); goto out_error; @@ -9025,7 +10709,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) LPFC_NVMET_RQE_DEF_COUNT, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3156 Failed allocate " "receive DRQ\n"); goto out_error; @@ -9035,6 +10719,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) } } +#if (IS_ENABLED(CONFIG_NVME_FC)) /* Clear NVME stats */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { @@ -9042,6 +10727,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(phba->sli4_hba.hdwq[idx].nvme_cstat)); } } +#endif /* Clear SCSI stats */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { @@ -9216,7 +10902,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, int rc; if (!eq || !cq || !wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6085 Fast-path %s (%d) not allocated\n", ((eq) ? ((cq) ? "WQ" : "CQ") : "EQ"), qidx); return -ENOMEM; @@ -9226,9 +10912,9 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, rc = lpfc_cq_create(phba, cq, eq, (qtype == LPFC_MBOX) ? LPFC_MCQ : LPFC_WCQ, qtype); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6086 Failed setup of CQ (%d), rc = 0x%x\n", - qidx, (uint32_t)rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6086 Failed setup of CQ (%d), rc = 0x%x\n", + qidx, (uint32_t)rc); return rc; } @@ -9244,7 +10930,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, /* create the wq */ rc = lpfc_wq_create(phba, wq, cq, qtype); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4618 Fail setup fastpath WQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); /* no need to tear down cq - caller will do so */ @@ -9262,9 +10948,9 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, } else { rc = lpfc_mq_create(phba, wq, cq, LPFC_MBOX); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0539 Failed setup of slow-path MQ: " - "rc = 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0539 Failed setup of slow-path MQ: " + "rc = 0x%x\n", rc); /* no need to tear down cq - caller will do so */ return rc; } @@ -9337,7 +11023,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Check for dual-ULP support */ mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3249 Unable to allocate memory for " "QUERY_FW_CFG mailbox command\n"); return -ENOMEM; @@ -9355,11 +11041,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3250 QUERY_FW_CFG mailbox failed with status " "x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); rc = -ENXIO; goto out_error; } @@ -9375,7 +11062,8 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) "ulp1_mode:x%x\n", phba->sli4_hba.fw_func_mode, phba->sli4_hba.ulp0_mode, phba->sli4_hba.ulp1_mode); - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); /* * Set up HBA Event Queues (EQs) @@ -9384,7 +11072,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up HBA event queue */ if (!qp) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3147 Fast-path EQs not allocated\n"); rc = -ENOMEM; goto out_error; @@ -9408,7 +11096,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq, phba->cfg_fcp_imax); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0523 Failed setup of fast-path" " EQ (%d), rc = 0x%x\n", cpup->eq, (uint32_t)rc); @@ -9440,7 +11128,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qidx, LPFC_IO); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0535 Failed to setup fastpath " "IO WQ/CQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); @@ -9455,7 +11143,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up slow-path MBOX CQ/MQ */ if (!phba->sli4_hba.mbx_cq || !phba->sli4_hba.mbx_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0528 %s not allocated\n", phba->sli4_hba.mbx_cq ? "Mailbox WQ" : "Mailbox CQ"); @@ -9468,14 +11156,14 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.mbx_wq, NULL, 0, LPFC_MBOX); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0529 Failed setup of mailbox WQ/CQ: rc = 0x%x\n", (uint32_t)rc); goto out_destroy; } if (phba->nvmet_support) { if (!phba->sli4_hba.nvmet_cqset) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3165 Fast-path NVME CQ Set " "array not allocated\n"); rc = -ENOMEM; @@ -9487,7 +11175,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qp, LPFC_WCQ, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3164 Failed setup of NVME CQ " "Set, rc = 0x%x\n", (uint32_t)rc); @@ -9499,7 +11187,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qp[0].hba_eq, LPFC_WCQ, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6089 Failed setup NVMET CQ: " "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9516,7 +11204,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up slow-path ELS WQ/CQ */ if (!phba->sli4_hba.els_cq || !phba->sli4_hba.els_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0530 ELS %s not allocated\n", phba->sli4_hba.els_cq ? "WQ" : "CQ"); rc = -ENOMEM; @@ -9526,10 +11214,11 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_cq, phba->sli4_hba.els_wq, NULL, 0, LPFC_ELS); + if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0525 Failed setup of ELS WQ/CQ: rc = 0x%x\n", - (uint32_t)rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "4101 Failed setup of ELS WQ/CQ: rc = 0x%x\n", + (uint32_t)rc); goto out_destroy; } lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -9540,7 +11229,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { /* Set up NVME LS Complete Queue */ if (!phba->sli4_hba.nvmels_cq || !phba->sli4_hba.nvmels_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6091 LS %s not allocated\n", phba->sli4_hba.nvmels_cq ? "WQ" : "CQ"); rc = -ENOMEM; @@ -9551,9 +11240,9 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmels_wq, NULL, 0, LPFC_NVME_LS); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0526 Failed setup of NVVME LS WQ/CQ: " - "rc = 0x%x\n", (uint32_t)rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "4102 Failed setup of NVVME LS WQ/CQ: " + "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; } @@ -9571,7 +11260,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if ((!phba->sli4_hba.nvmet_cqset) || (!phba->sli4_hba.nvmet_mrq_hdr) || (!phba->sli4_hba.nvmet_mrq_data)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6130 MRQ CQ Queues not " "allocated\n"); rc = -ENOMEM; @@ -9584,7 +11273,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmet_cqset, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6098 Failed setup of NVMET " "MRQ: rc = 0x%x\n", (uint32_t)rc); @@ -9598,7 +11287,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmet_cqset[0], LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6057 Failed setup of NVMET " "Receive Queue: rc = 0x%x\n", (uint32_t)rc); @@ -9617,7 +11306,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) } if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0540 Receive Queue not allocated\n"); rc = -ENOMEM; goto out_destroy; @@ -9626,7 +11315,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, phba->sli4_hba.els_cq, LPFC_USOL); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0541 Failed setup of Receive Queue: " "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9651,10 +11340,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (phba->sli4_hba.cq_max) { kfree(phba->sli4_hba.cq_lookup); - phba->sli4_hba.cq_lookup = kcalloc((phba->sli4_hba.cq_max + 1), + phba->sli4_hba.cq_lookup = kzalloc((phba->sli4_hba.cq_max + 1) * sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.cq_lookup) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0549 Failed setup of CQ Lookup table: " "size 0x%x\n", phba->sli4_hba.cq_max); rc = -ENOMEM; @@ -9901,26 +11590,28 @@ lpfc_sli4_cq_event_release(struct lpfc_hba *phba, static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) { - LIST_HEAD(cqelist); - struct lpfc_cq_event *cqe; + LIST_HEAD(cq_event_list); + struct lpfc_cq_event *cq_event; unsigned long iflags; /* Retrieve all the pending WCQEs from pending WCQE lists */ - spin_lock_irqsave(&phba->hbalock, iflags); - /* Pending FCP XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, - &cqelist); - /* Pending ELS XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, - &cqelist); - /* Pending asynnc events */ - list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, - &cqelist); - spin_unlock_irqrestore(&phba->hbalock, iflags); - while (!list_empty(&cqelist)) { - list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list); - lpfc_sli4_cq_event_release(phba, cqe); + /* Pending ELS XRI abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); + list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); + + /* Pending asynnc events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); + list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); + + while (!list_empty(&cq_event_list)) { + list_remove_head(&cq_event_list, cq_event, + struct lpfc_cq_event, list); + lpfc_sli4_cq_event_release(phba, cq_event); } } @@ -9954,7 +11645,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0494 Unable to allocate memory for " "issuing SLI_FUNCTION_RESET mailbox " "command\n"); @@ -9971,9 +11662,10 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0495 SLI_FUNCTION_RESET mailbox " "failed with status x%x add_status x%x," " mbx status x%x\n", @@ -9989,7 +11681,7 @@ wait: * up to 30 seconds. If the port doesn't respond, treat * it as an error. */ - for (rdy_chk = 0; rdy_chk < 1500; rdy_chk++) { + for (rdy_chk = 0; rdy_chk < 3000; rdy_chk++) { if (lpfc_readl(phba->sli4_hba.u.if_type2. STATUSregaddr, ®_data.word0)) { rc = -ENODEV; @@ -10005,7 +11697,7 @@ wait: phba->sli4_hba.u.if_type2.ERR1regaddr); phba->work_status[1] = readl( phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2890 Port not ready, port status reg " "0x%x error 1=0x%x, error 2=0x%x\n", reg_data.word0, @@ -10047,7 +11739,7 @@ wait: out: /* Catch the not-ready port failure after a port reset. */ if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3317 HBA not functional: IP Reset Failed " "try: echo fw_reset > board_mode\n"); rc = -ENODEV; @@ -10097,7 +11789,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) /* There is no SLI3 failback for SLI4 devices. */ if (bf_get(lpfc_sli_intf_valid, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_VALID) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2894 SLI_INTF reg contents invalid " "sli_intf reg 0x%x\n", phba->sli4_hba.sli_intf.word0); @@ -10162,7 +11854,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) ioremap(phba->pci_bar1_map, bar1map_len); if (!phba->sli4_hba.ctrl_regs_memmap_p) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA " "control registers.\n"); error = -ENOMEM; @@ -10188,7 +11880,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) phba->sli4_hba.drbl_regs_memmap_p = ioremap(phba->pci_bar1_map, bar1map_len); if (!phba->sli4_hba.drbl_regs_memmap_p) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA doorbell registers.\n"); error = -ENOMEM; goto out_iounmap_conf; @@ -10210,7 +11902,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) ioremap(phba->pci_bar2_map, bar2map_len); if (!phba->sli4_hba.drbl_regs_memmap_p) { - dev_err(&pdev->dev, + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA" " doorbell registers.\n"); error = -ENOMEM; @@ -10227,8 +11919,9 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) } } - if (if_type == LPFC_SLI_INTF_IF_TYPE_6 && - pci_resource_start(pdev, PCI_64BIT_BAR4)) { +#ifndef BUILD_BRCMFCOE + if ((if_type == LPFC_SLI_INTF_IF_TYPE_6) && + (pci_resource_start(pdev, PCI_64BIT_BAR4))) { /* * Map SLI4 if type 6 HBA DPP Register base to a kernel * virtual address and setup the registers. @@ -10236,18 +11929,17 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4); bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4); phba->sli4_hba.dpp_regs_memmap_p = - ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->sli4_hba.dpp_regs_memmap_p) { - dev_err(&pdev->dev, + ioremap_wc(phba->pci_bar2_map, bar2map_len); + if (!phba->sli4_hba.dpp_regs_memmap_p) + /* not a failure, we simply won't use dpp */ + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA dpp registers.\n"); - error = -ENOMEM; - goto out_iounmap_ctrl; - } phba->pci_bar4_memmap_p = phba->sli4_hba.dpp_regs_memmap_p; } +#endif /* Set up the EQ/CQ register handeling functions now */ - switch (if_type) { + switch(if_type) { case LPFC_SLI_INTF_IF_TYPE_0: case LPFC_SLI_INTF_IF_TYPE_2: phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_eq_clr_intr; @@ -10300,6 +11992,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) case LPFC_SLI_INTF_IF_TYPE_6: iounmap(phba->sli4_hba.drbl_regs_memmap_p); iounmap(phba->sli4_hba.conf_regs_memmap_p); + if (phba->sli4_hba.dpp_regs_memmap_p) + iounmap(phba->sli4_hba.dpp_regs_memmap_p); break; case LPFC_SLI_INTF_IF_TYPE_1: default: @@ -10325,23 +12019,34 @@ static int lpfc_sli_enable_msix(struct lpfc_hba *phba) { int rc; + int i; LPFC_MBOXQ_t *pmb; /* Set up MSI-X multi-message vectors */ - rc = pci_alloc_irq_vectors(phba->pcidev, - LPFC_MSIX_VECTORS, LPFC_MSIX_VECTORS, PCI_IRQ_MSIX); - if (rc < 0) { + for (i = 0; i < LPFC_MSIX_VECTORS; i++) + phba->msix_entries[i].entry = i; + + /* Configure MSI-X capability structure */ + rc = pci_enable_msix_exact(phba->pcidev, phba->msix_entries, + LPFC_MSIX_VECTORS); + if (rc) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0420 PCI enable MSI-X failed (%d)\n", rc); - goto vec_fail_out; + goto msi_fail_out; } + for (i = 0; i < LPFC_MSIX_VECTORS; i++) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0477 MSI-X entry[%d]: vector=x%x " + "message=%d\n", i, + phba->msix_entries[i].vector, + phba->msix_entries[i].entry); /* * Assign MSI-X vectors to interrupt handlers */ /* vector-0 is associated to slow-path handler */ - rc = request_irq(pci_irq_vector(phba->pcidev, 0), + rc = request_irq(phba->msix_entries[0].vector, &lpfc_sli_sp_intr_handler, 0, LPFC_SP_DRIVER_HANDLER_NAME, phba); if (rc) { @@ -10352,10 +12057,9 @@ lpfc_sli_enable_msix(struct lpfc_hba *phba) } /* vector-1 is associated to fast-path handler */ - rc = request_irq(pci_irq_vector(phba->pcidev, 1), + rc = request_irq(phba->msix_entries[1].vector, &lpfc_sli_fp_intr_handler, 0, LPFC_FP_DRIVER_HANDLER_NAME, phba); - if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0429 MSI-X fast-path request_irq failed " @@ -10370,7 +12074,7 @@ lpfc_sli_enable_msix(struct lpfc_hba *phba) if (!pmb) { rc = -ENOMEM; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0474 Unable to allocate memory for issuing " "MBOX_CONFIG_MSI command\n"); goto mem_fail_out; @@ -10397,17 +12101,16 @@ mbx_fail_out: mem_fail_out: /* free the irq already requested */ - free_irq(pci_irq_vector(phba->pcidev, 1), phba); + free_irq(phba->msix_entries[1].vector, phba); irq_fail_out: /* free the irq already requested */ - free_irq(pci_irq_vector(phba->pcidev, 0), phba); + free_irq(phba->msix_entries[0].vector, phba); msi_fail_out: /* Unconfigure MSI-X capability structure */ - pci_free_irq_vectors(phba->pcidev); + pci_disable_msix(phba->pcidev); -vec_fail_out: return rc; } @@ -10521,16 +12224,18 @@ lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) static void lpfc_sli_disable_intr(struct lpfc_hba *phba) { - int nr_irqs, i; + int i; - if (phba->intr_type == MSIX) - nr_irqs = LPFC_MSIX_VECTORS; - else - nr_irqs = 1; - - for (i = 0; i < nr_irqs; i++) - free_irq(pci_irq_vector(phba->pcidev, i), phba); - pci_free_irq_vectors(phba->pcidev); + if (phba->intr_type == MSIX) { + for (i = 0; i < LPFC_MSIX_VECTORS; i++) + free_irq(phba->msix_entries[i].vector, phba); + pci_disable_msix(phba->pcidev); + } else if (phba->intr_type == MSI) { + free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); + } else { + free_irq(phba->pcidev->irq, phba); + } /* Reset interrupt management states */ phba->intr_type = NONE; @@ -10561,7 +12266,6 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) */ if ((match == LPFC_FIND_BY_EQ) && (cpup->flag & LPFC_CPU_FIRST_IRQ) && - (cpup->irq != LPFC_VECTOR_MAP_EMPTY) && (cpup->eq == id)) return cpu; @@ -10599,6 +12303,75 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu, } #endif +/* + * lpfc_assign_eq_map_info - Assigns eq for vector_map structure + * @phba: pointer to lpfc hba data structure. + * @eqidx: index for eq and irq vector + * @flag: flags to set for vector_map structure + * @cpu: cpu used to index vector_map structure + * + * The routine assigns eq info into vector_map structure + */ +static inline void +lpfc_assign_eq_map_info(struct lpfc_hba *phba, uint16_t eqidx, uint16_t flag, + unsigned int cpu) +{ + struct lpfc_vector_map_info *cpup = &phba->sli4_hba.cpu_map[cpu]; + struct lpfc_hba_eq_hdl *eqhdl = lpfc_get_eq_hdl(eqidx); + + cpup->eq = eqidx; + cpup->flag |= flag; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3336 Set Affinity: CPU %d irq %d eq %d flag x%x\n", + cpu, eqhdl->irq, cpup->eq, cpup->flag); +} + +/** + * lpfc_cpu_map_array_init - Initialize cpu_map structure + * @phba: pointer to lpfc hba data structure. + * + * The routine initializes the cpu_map array structure + */ +static void +lpfc_cpu_map_array_init(struct lpfc_hba *phba) +{ + struct lpfc_vector_map_info *cpup; + struct lpfc_eq_intr_info *eqi; + int cpu; + + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; + cpup->core_id = LPFC_VECTOR_MAP_EMPTY; + cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; + cpup->eq = LPFC_VECTOR_MAP_EMPTY; + cpup->flag = 0; + eqi = per_cpu_ptr(phba->sli4_hba.eq_info, cpu); + INIT_LIST_HEAD(&eqi->list); + eqi->icnt = 0; + } +} + +/** + * lpfc_hba_eq_hdl_array_init - Initialize hba_eq_hdl structure + * @phba: pointer to lpfc hba data structure. + * + * The routine initializes the hba_eq_hdl array structure + */ +static void +lpfc_hba_eq_hdl_array_init(struct lpfc_hba *phba) +{ + struct lpfc_hba_eq_hdl *eqhdl; + int i; + + for (i = 0; i < phba->cfg_irq_chann; i++) { + eqhdl = lpfc_get_eq_hdl(i); + eqhdl->irq = LPFC_VECTOR_MAP_EMPTY; + eqhdl->phba = phba; + } +} + /** * lpfc_cpu_affinity_check - Check vector CPU affinity mappings * @phba: pointer to lpfc hba data structure. @@ -10617,21 +12390,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) int max_core_id, min_core_id; struct lpfc_vector_map_info *cpup; struct lpfc_vector_map_info *new_cpup; - const struct cpumask *maskp; #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif - - /* Init cpu_map array */ - for_each_possible_cpu(cpu) { - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; - cpup->core_id = LPFC_VECTOR_MAP_EMPTY; - cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; - cpup->eq = LPFC_VECTOR_MAP_EMPTY; - cpup->irq = LPFC_VECTOR_MAP_EMPTY; - cpup->flag = 0; - } +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + struct lpfc_hdwq_stat *c_stat; +#endif max_phys_id = 0; min_phys_id = LPFC_VECTOR_MAP_EMPTY; @@ -10668,65 +12432,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) min_core_id = cpup->core_id; } - for_each_possible_cpu(i) { - struct lpfc_eq_intr_info *eqi = - per_cpu_ptr(phba->sli4_hba.eq_info, i); - - INIT_LIST_HEAD(&eqi->list); - eqi->icnt = 0; - } - - /* This loop sets up all CPUs that are affinitized with a - * irq vector assigned to the driver. All affinitized CPUs - * will get a link to that vectors IRQ and EQ. - * - * NULL affinity mask handling: - * If irq count is greater than one, log an error message. - * If the null mask is received for the first irq, find the - * first present cpu, and assign the eq index to ensure at - * least one EQ is assigned. - */ - for (idx = 0; idx < phba->cfg_irq_chann; idx++) { - /* Get a CPU mask for all CPUs affinitized to this vector */ - maskp = pci_irq_get_affinity(phba->pcidev, idx); - if (!maskp) { - if (phba->cfg_irq_chann > 1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3329 No affinity mask found " - "for vector %d (%d)\n", - idx, phba->cfg_irq_chann); - if (!idx) { - cpu = cpumask_first(cpu_present_mask); - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->eq = idx; - cpup->irq = pci_irq_vector(phba->pcidev, idx); - cpup->flag |= LPFC_CPU_FIRST_IRQ; - } - break; - } - - i = 0; - /* Loop through all CPUs associated with vector idx */ - for_each_cpu_and(cpu, maskp, cpu_present_mask) { - /* Set the EQ index and IRQ for that vector */ - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->eq = idx; - cpup->irq = pci_irq_vector(phba->pcidev, idx); - - /* If this is the first CPU thats assigned to this - * vector, set LPFC_CPU_FIRST_IRQ. - */ - if (!i) - cpup->flag |= LPFC_CPU_FIRST_IRQ; - i++; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3336 Set Affinity: CPU %d " - "irq %d eq %d flag x%x\n", - cpu, cpup->irq, cpup->eq, cpup->flag); - } - } - /* After looking at each irq vector assigned to this pcidev, its * possible to see that not ALL CPUs have been accounted for. * Next we will set any unassigned (unaffinitized) cpu map @@ -10752,7 +12457,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && - (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY) && (new_cpup->phys_id == cpup->phys_id)) goto found_same; new_cpu = cpumask_next( @@ -10765,7 +12470,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) found_same: /* We found a matching phys_id, so copy the IRQ info */ cpup->eq = new_cpup->eq; - cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the * chance of having multiple unassigned CPU entries @@ -10777,9 +12481,10 @@ found_same: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3337 Set Affinity: CPU %d " - "irq %d from id %d same " + "eq %d from peer cpu %d same " "phys_id (%d)\n", - cpu, cpup->irq, new_cpu, cpup->phys_id); + cpu, cpup->eq, new_cpu, + cpup->phys_id); } } @@ -10803,7 +12508,7 @@ found_same: for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && - (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY)) + (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY)) goto found_any; new_cpu = cpumask_next( new_cpu, cpu_present_mask); @@ -10813,13 +12518,12 @@ found_same: /* We should never leave an entry unassigned */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3339 Set Affinity: CPU %d " - "irq %d UNASSIGNED\n", - cpup->hdwq, cpup->irq); + "eq %d UNASSIGNED\n", + cpup->hdwq, cpup->eq); continue; found_any: /* We found an available entry, copy the IRQ info */ cpup->eq = new_cpup->eq; - cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the * chance of having multiple unassigned CPU entries @@ -10831,8 +12535,8 @@ found_any: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3338 Set Affinity: CPU %d " - "irq %d from id %d (%d/%d)\n", - cpu, cpup->irq, new_cpu, + "eq %d from peer cpu %d (%d/%d)\n", + cpu, cpup->eq, new_cpu, new_cpup->phys_id, new_cpup->core_id); } } @@ -10853,11 +12557,11 @@ found_any: idx++; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3333 Set Affinity: CPU %d (phys %d core %d): " - "hdwq %d eq %d irq %d flg x%x\n", + "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, - cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + cpup->hdwq, cpup->eq, cpup->flag); } - /* Finally we need to associate a hdwq with each cpu_map entry + /* Associate a hdwq with each cpu_map entry * This will be 1 to 1 - hdwq to cpu, unless there are less * hardware queues then CPUs. For that case we will just round-robin * the available hardware queues as they get assigned to CPUs. @@ -10931,9 +12635,33 @@ found_any: logit: lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3335 Set Affinity: CPU %d (phys %d core %d): " - "hdwq %d eq %d irq %d flg x%x\n", + "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, - cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + cpup->hdwq, cpup->eq, cpup->flag); + } + + /* + * Initialize the cpu_map slots for not-present cpus in case + * a cpu is hot-added. Perform a simple hdwq round robin assignment. + */ + idx = 0; + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, cpu); + c_stat->hdwq_no = cpup->hdwq; +#endif + if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) + continue; + + cpup->hdwq = idx++ % phba->cfg_hdw_queue; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + c_stat->hdwq_no = cpup->hdwq; +#endif + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3340 Set Affinity: not present " + "CPU %d hdwq %d\n", + cpu, cpup->hdwq); } /* The cpu_map array will be used later during initialization @@ -10949,17 +12677,19 @@ found_any: * @cpu: cpu going offline * @eqlist: */ -static void +static int lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, struct list_head *eqlist) { - struct lpfc_vector_map_info *map; const struct cpumask *maskp; struct lpfc_queue *eq; - unsigned int i; - cpumask_t tmp; + struct cpumask *tmp; u16 idx; + tmp = kzalloc(cpumask_size(), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { maskp = pci_irq_get_affinity(phba->pcidev, idx); if (!maskp) @@ -10969,7 +12699,7 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * then we don't need to poll the eq attached * to it. */ - if (!cpumask_and(&tmp, maskp, cpumask_of(cpu))) + if (!cpumask_and(tmp, maskp, cpumask_of(cpu))) continue; /* get the cpus that are online and are affini- * tized to this irq vector. If the count is @@ -10977,8 +12707,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * down this vector. Since this cpu has not * gone offline yet, we need >1. */ - cpumask_and(&tmp, maskp, cpu_online_mask); - if (cpumask_weight(&tmp) > 1) + cpumask_and(tmp, maskp, cpu_online_mask); + if (cpumask_weight(tmp) > 1) continue; /* Now that we have an irq to shutdown, get the eq @@ -10986,16 +12716,11 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * the software can share an eq, but eventually * only eq will be mapped to this vector */ - for_each_possible_cpu(i) { - map = &phba->sli4_hba.cpu_map[i]; - if (!(map->irq == pci_irq_vector(phba->pcidev, idx))) - continue; - eq = phba->sli4_hba.hdwq[map->hdwq].hba_eq; - list_add(&eq->_poll_list, eqlist); - /* 1 is good enough. others will be a copy of this */ - break; - } + eq = phba->sli4_hba.hba_eq_hdl[idx].eq; + list_add(&eq->_poll_list, eqlist); } + kfree(tmp); + return 0; } static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) @@ -11028,11 +12753,9 @@ static void lpfc_cpuhp_add(struct lpfc_hba *phba) rcu_read_lock(); - if (!list_empty(&phba->poll_list)) { - timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); + if (!list_empty(&phba->poll_list)) mod_timer(&phba->cpuhp_poll_timer, jiffies + msecs_to_jiffies(LPFC_POLL_HB)); - } rcu_read_unlock(); @@ -11056,6 +12779,99 @@ static int __lpfc_cpuhp_checks(struct lpfc_hba *phba, int *retval) return false; } +/** + * lpfc_irq_set_aff - set IRQ affinity + * @eqhdl: EQ handle + * @cpu: cpu to set affinity + * + **/ +static inline void +lpfc_irq_set_aff(struct lpfc_hba_eq_hdl *eqhdl, unsigned int cpu) +{ + cpumask_clear(&eqhdl->aff_mask); + cpumask_set_cpu(cpu, &eqhdl->aff_mask); + irq_set_status_flags(eqhdl->irq, IRQ_NO_BALANCING); + irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask); +} + +/** + * lpfc_irq_clear_aff - clear IRQ affinity + * @eqhdl: EQ handle + * + **/ +static inline void +lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl) +{ + cpumask_clear(&eqhdl->aff_mask); + irq_clear_status_flags(eqhdl->irq, IRQ_NO_BALANCING); +} + +/** + * lpfc_irq_rebalance - rebalances IRQ affinity according to cpuhp event + * @phba: pointer to HBA context object. + * @cpu: cpu going offline/online + * @offline: true, cpu is going offline. false, cpu is coming online. + * + * If cpu is going offline, we'll try our best effort to find the next + * online cpu on the phba's original_mask and migrate all offlining IRQ + * affinities. + * + * If cpu is coming online, reaffinitize the IRQ back to the onlining cpu. + * + * Note: Call only if NUMA or NHT mode is enabled, otherwise rely on + * PCI_IRQ_AFFINITY to auto-manage IRQ affinity. + * + **/ +static void +lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline) +{ + struct lpfc_vector_map_info *cpup; + struct cpumask *aff_mask; + unsigned int cpu_select, cpu_next, idx; + const struct cpumask *orig_mask; + + if (phba->irq_chann_mode == NORMAL_MODE) + return; + + orig_mask = &phba->sli4_hba.irq_aff_mask; + + if (!cpumask_test_cpu(cpu, orig_mask)) + return; + + cpup = &phba->sli4_hba.cpu_map[cpu]; + + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) + return; + + if (offline) { + /* Find next online CPU on original mask */ + cpu_next = cpumask_next_wrap(cpu, orig_mask, cpu, true); + cpu_select = lpfc_next_online_cpu(orig_mask, cpu_next); + + /* Found a valid CPU */ + if ((cpu_select < nr_cpu_ids) && (cpu_select != cpu)) { + /* Go through each eqhdl and ensure offlining + * cpu aff_mask is migrated + */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + aff_mask = lpfc_get_aff_mask(idx); + + /* Migrate affinity */ + if (cpumask_test_cpu(cpu, aff_mask)) + lpfc_irq_set_aff(lpfc_get_eq_hdl(idx), + cpu_select); + } + } else { + /* Rely on irqbalance if no online CPUs left on NUMA */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) + lpfc_irq_clear_aff(lpfc_get_eq_hdl(idx)); + } + } else { + /* Migrate affinity back to this CPU */ + lpfc_irq_set_aff(lpfc_get_eq_hdl(cpup->eq), cpu); + } +} + static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) { struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp); @@ -11064,14 +12880,19 @@ static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) int retval; if (!phba) { - WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id()); + WARN_ONCE(!phba, "cpu: %u. phba:%px.", raw_smp_processor_id(), + phba); return 0; } if (__lpfc_cpuhp_checks(phba, &retval)) return retval; - lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + lpfc_irq_rebalance(phba, cpu, true); + + retval = lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + if (retval) + return retval; /* start polling on these eq's */ list_for_each_entry_safe(eq, next, &eqlist, _poll_list) { @@ -11090,13 +12911,16 @@ static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node) int retval; if (!phba) { - WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id()); + WARN_ONCE(!phba, "cpu: %u. phba:%px.", raw_smp_processor_id(), + phba); return 0; } if (__lpfc_cpuhp_checks(phba, &retval)) return retval; + lpfc_irq_rebalance(phba, cpu, false); + list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list) { n = lpfc_find_cpu_handle(phba, eq->hdwq, LPFC_FIND_BY_HDWQ); if (n == cpu) @@ -11111,7 +12935,24 @@ static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node) * @phba: pointer to lpfc hba data structure. * * This routine is invoked to enable the MSI-X interrupt vectors to device - * with SLI-4 interface spec. + * with SLI-4 interface spec. It also allocates MSI-X vectors and maps them + * to cpus on the system. + * + * When cfg_irq_numa is enabled, the adapter will only allocate vectors for + * the number of cpus on the same numa node as this adapter. The vectors are + * allocated without requesting OS affinity mapping. A vector will be + * allocated and assigned to each online and offline cpu. If the cpu is + * online, then affinity will be set to that cpu. If the cpu is offline, then + * affinity will be set to the nearest peer cpu within the numa node that is + * online. If there are no online cpus within the numa node, affinity is not + * assigned and the OS may do as it pleases. Note: cpu vector affinity mapping + * is consistent with the way cpu online/offline is handled when cfg_irq_numa is + * configured. + * + * If numa mode is not enabled and there is more than 1 vector allocated, then + * the driver relies on the managed irq interface where the OS assigns vector to + * cpu affinity. The driver will then use that affinity mapping to setup its + * cpu mapping table. * * Return codes * 0 - successful @@ -11122,67 +12963,163 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) { int vectors, rc, index; char *name; + const struct cpumask *aff_mask = NULL; + unsigned int cpu = 0, cpu_cnt = 0, cpu_select = nr_cpu_ids; + struct lpfc_vector_map_info *cpup; + struct lpfc_hba_eq_hdl *eqhdl; + const struct cpumask *maskp; + unsigned int flags = PCI_IRQ_MSIX; - /* Set up MSI-X multi-message vectors */ + /* Configure MSI-X capability structure */ vectors = phba->cfg_irq_chann; - rc = pci_alloc_irq_vectors(phba->pcidev, - 1, - vectors, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); + if (phba->irq_chann_mode != NORMAL_MODE) + aff_mask = &phba->sli4_hba.irq_aff_mask; + + if (aff_mask) { + cpu_cnt = cpumask_weight(aff_mask); + vectors = min(phba->cfg_irq_chann, cpu_cnt); + + /* cpu: iterates over aff_mask including offline or online + * cpu_select: iterates over online aff_mask to set affinity + */ + cpu = cpumask_first(aff_mask); + cpu_select = lpfc_next_online_cpu(aff_mask, cpu); + } else { + flags |= PCI_IRQ_AFFINITY; + } + + rc = pci_alloc_irq_vectors(phba->pcidev, 1, vectors, flags); if (rc < 0) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0484 PCI enable MSI-X failed (%d)\n", rc); - goto vec_fail_out; + goto msi_fail_out; } + vectors = rc; /* Assign MSI-X vectors to interrupt handlers */ for (index = 0; index < vectors; index++) { - name = phba->sli4_hba.hba_eq_hdl[index].handler_name; + eqhdl = lpfc_get_eq_hdl(index); + name = eqhdl->handler_name; memset(name, 0, LPFC_SLI4_HANDLER_NAME_SZ); snprintf(name, LPFC_SLI4_HANDLER_NAME_SZ, LPFC_DRIVER_HANDLER_NAME"%d", index); - phba->sli4_hba.hba_eq_hdl[index].idx = index; - phba->sli4_hba.hba_eq_hdl[index].phba = phba; + eqhdl->idx = index; rc = request_irq(pci_irq_vector(phba->pcidev, index), - &lpfc_sli4_hba_intr_handler, 0, - name, - &phba->sli4_hba.hba_eq_hdl[index]); + &lpfc_sli4_hba_intr_handler, 0, + name, eqhdl); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0486 MSI-X fast-path (%d) " "request_irq failed (%d)\n", index, rc); goto cfg_fail_out; } + + eqhdl->irq = pci_irq_vector(phba->pcidev, index); + + if (aff_mask) { + /* If found a neighboring online cpu, set affinity */ + if (cpu_select < nr_cpu_ids) + lpfc_irq_set_aff(eqhdl, cpu_select); + + /* Assign EQ to cpu_map */ + lpfc_assign_eq_map_info(phba, index, + LPFC_CPU_FIRST_IRQ, + cpu); + + /* Iterate to next offline or online cpu in aff_mask */ + cpu = cpumask_next(cpu, aff_mask); + + /* Find next online cpu in aff_mask to set affinity */ + cpu_select = lpfc_next_online_cpu(aff_mask, cpu); + } else if (vectors == 1) { + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, index, LPFC_CPU_FIRST_IRQ, + cpu); + } else { + maskp = pci_irq_get_affinity(phba->pcidev, index); + + /* Loop through all CPUs associated with vector index */ + for_each_cpu_and(cpu, maskp, cpu_present_mask) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* If this is the first CPU thats assigned to + * this vector, set LPFC_CPU_FIRST_IRQ. + * + * With certain platforms its possible that irq + * vectors are affinitized to all the cpu's. + * This can result in each cpu_map.eq to be set + * to the last vector, resulting in overwrite + * of all the previous cpu_map.eq. Ensure that + * each vector receives a place in cpu_map. + * Later call to lpfc_cpu_affinity_check will + * ensure we are nicely balanced out. + */ + if (cpup->eq != LPFC_VECTOR_MAP_EMPTY) + continue; + lpfc_assign_eq_map_info(phba, index, + LPFC_CPU_FIRST_IRQ, + cpu); + break; + } + } } if (vectors != phba->cfg_irq_chann) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3238 Reducing IO channels to match number of " "MSI-X vectors, requested %d got %d\n", phba->cfg_irq_chann, vectors); if (phba->cfg_irq_chann > vectors) phba->cfg_irq_chann = vectors; - if (phba->nvmet_support && (phba->cfg_nvmet_mrq > vectors)) - phba->cfg_nvmet_mrq = vectors; } return rc; cfg_fail_out: /* free the irq already requested */ - for (--index; index >= 0; index--) - free_irq(pci_irq_vector(phba->pcidev, index), - &phba->sli4_hba.hba_eq_hdl[index]); + for (--index; index >= 0; index--) { + eqhdl = lpfc_get_eq_hdl(index); + lpfc_irq_clear_aff(eqhdl); + irq_set_affinity_hint(eqhdl->irq, NULL); + free_irq(eqhdl->irq, eqhdl); + } /* Unconfigure MSI-X capability structure */ - pci_free_irq_vectors(phba->pcidev); + pci_disable_msix(phba->pcidev); -vec_fail_out: +msi_fail_out: return rc; } +/** + * lpfc_sli4_disable_msix - Disable MSI-X interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release the MSI-X vectors and then disable the + * MSI-X interrupt mode to device with SLI-4 interface spec. + **/ +static void +lpfc_sli4_disable_msix(struct lpfc_hba *phba) +{ + int index; + struct lpfc_hba_eq_hdl *eqhdl; + + /* Free up MSI-X multi-message vectors */ + for (index = 0; index < phba->cfg_irq_chann; index++) { + eqhdl = lpfc_get_eq_hdl(index); + lpfc_irq_clear_aff(eqhdl); + irq_set_affinity_hint(eqhdl->irq, NULL); + free_irq(eqhdl->irq, eqhdl); + } + /* Disable MSI-X */ + pci_disable_msix(phba->pcidev); + + return; +} + /** * lpfc_sli4_enable_msi - Enable MSI interrupt mode to SLI-4 device * @phba: pointer to lpfc hba data structure. @@ -11201,6 +13138,8 @@ static int lpfc_sli4_enable_msi(struct lpfc_hba *phba) { int rc, index; + unsigned int cpu; + struct lpfc_hba_eq_hdl *eqhdl; rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_AFFINITY); @@ -11222,14 +13161,38 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) return rc; } + eqhdl = lpfc_get_eq_hdl(0); + eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, cpu); + for (index = 0; index < phba->cfg_irq_chann; index++) { - phba->sli4_hba.hba_eq_hdl[index].idx = index; - phba->sli4_hba.hba_eq_hdl[index].phba = phba; + eqhdl = lpfc_get_eq_hdl(index); + eqhdl->idx = index; } return 0; } +/** + * lpfc_sli4_disable_msi - Disable MSI interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to disable the MSI interrupt mode to device with + * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has + * done request_irq() on before calling pci_disable_msi(). Failure to do so + * results in a BUG_ON() and a device will be left with MSI enabled and leaks + * its vector. + **/ +static void +lpfc_sli4_disable_msi(struct lpfc_hba *phba) +{ + free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); + return; +} + /** * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device * @phba: pointer to lpfc hba data structure. @@ -11282,15 +13245,21 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) IRQF_SHARED, LPFC_DRIVER_NAME, phba); if (!retval) { struct lpfc_hba_eq_hdl *eqhdl; + unsigned int cpu; /* Indicate initialization to INTx mode */ phba->intr_type = INTx; intr_mode = 0; + eqhdl = lpfc_get_eq_hdl(0); + eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, + cpu); for (idx = 0; idx < phba->cfg_irq_chann; idx++) { - eqhdl = &phba->sli4_hba.hba_eq_hdl[idx]; + eqhdl = lpfc_get_eq_hdl(idx); eqhdl->idx = idx; - eqhdl->phba = phba; } } } @@ -11310,22 +13279,12 @@ static void lpfc_sli4_disable_intr(struct lpfc_hba *phba) { /* Disable the currently initialized interrupt mode */ - if (phba->intr_type == MSIX) { - int index; - - /* Free up MSI-X multi-message vectors */ - for (index = 0; index < phba->cfg_irq_chann; index++) { - irq_set_affinity_hint( - pci_irq_vector(phba->pcidev, index), - NULL); - free_irq(pci_irq_vector(phba->pcidev, index), - &phba->sli4_hba.hba_eq_hdl[index]); - } - } else { + if (phba->intr_type == MSIX) + lpfc_sli4_disable_msix(phba); + else if (phba->intr_type == MSI) + lpfc_sli4_disable_msi(phba); + else if (phba->intr_type == INTx) free_irq(phba->pcidev->irq, phba); - } - - pci_free_irq_vectors(phba->pcidev); /* Reset interrupt management states */ phba->intr_type = NONE; @@ -11416,17 +13375,17 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) while (!els_xri_cmpl || !io_xri_cmpl || !nvmet_xri_cmpl) { if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) { if (!nvmet_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6424 NVMET XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); if (!io_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6100 IO XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); if (!els_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2878 ELS XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); @@ -11476,9 +13435,15 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) struct pci_dev *pdev = phba->pcidev; lpfc_stop_hba_timers(phba); + hrtimer_cancel(&phba->cmf_timer); + if (phba->pport) phba->sli4_hba.intr_enable = 0; +#ifndef BUILD_BRCMFCOE + if (!list_empty(&phba->lpfc_auth_active_cfg_list)) + lpfc_auth_free_active_cfg_list(phba); +#endif /* * Gracefully wait out the potential current outstanding asynchronous * mailbox command. @@ -11512,8 +13477,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) lpfc_sli4_xri_exchange_busy_wait(phba); /* per-phba callback de-registration for hotplug event */ - if (phba->pport) - lpfc_cpuhp_remove(phba); + lpfc_cpuhp_remove(phba); /* Disable PCI subsystem interrupt */ lpfc_sli4_disable_intr(phba); @@ -11546,13 +13510,315 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) phba->pport->work_port_events = 0; } + /** + * lpfc_pc_sli4_params_get - Get the SLI4_PARAMS port capabilities. + * @phba: Pointer to HBA context object. + * @mboxq: Pointer to the mailboxq memory for the mailbox command response. + * + * This function is called in the SLI4 code path to read the port's + * sli4 capabilities. + * + * This function may be be called from any context that can block-wait + * for the completion. The expectation is that this routine is called + * typically from probe_one or from the online routine. + **/ +int +lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + int rc; + struct lpfc_mqe *mqe; + struct lpfc_pc_sli4_params *sli4_params; + uint32_t mbox_tmo; + + rc = 0; + mqe = &mboxq->u.mqe; + + /* Read the port's SLI4 Parameters port capabilities */ + lpfc_pc_sli4_params(mboxq); + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); + rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + } + + if (unlikely(rc)) + return 1; + + sli4_params = &phba->sli4_hba.pc_sli4_params; + sli4_params->if_type = bf_get(if_type, &mqe->un.sli4_params); + sli4_params->sli_rev = bf_get(sli_rev, &mqe->un.sli4_params); + sli4_params->sli_family = bf_get(sli_family, &mqe->un.sli4_params); + sli4_params->featurelevel_1 = bf_get(featurelevel_1, + &mqe->un.sli4_params); + sli4_params->featurelevel_2 = bf_get(featurelevel_2, + &mqe->un.sli4_params); + sli4_params->proto_types = mqe->un.sli4_params.word3; + sli4_params->sge_supp_len = mqe->un.sli4_params.sge_supp_len; + sli4_params->if_page_sz = bf_get(if_page_sz, &mqe->un.sli4_params); + sli4_params->rq_db_window = bf_get(rq_db_window, &mqe->un.sli4_params); + sli4_params->loopbk_scope = bf_get(loopbk_scope, &mqe->un.sli4_params); + sli4_params->eq_pages_max = bf_get(eq_pages, &mqe->un.sli4_params); + sli4_params->eqe_size = bf_get(eqe_size, &mqe->un.sli4_params); + sli4_params->cq_pages_max = bf_get(cq_pages, &mqe->un.sli4_params); + sli4_params->cqe_size = bf_get(cqe_size, &mqe->un.sli4_params); + sli4_params->mq_pages_max = bf_get(mq_pages, &mqe->un.sli4_params); + sli4_params->mqe_size = bf_get(mqe_size, &mqe->un.sli4_params); + sli4_params->mq_elem_cnt = bf_get(mq_elem_cnt, &mqe->un.sli4_params); + sli4_params->wq_pages_max = bf_get(wq_pages, &mqe->un.sli4_params); + sli4_params->wqe_size = bf_get(wqe_size, &mqe->un.sli4_params); + sli4_params->rq_pages_max = bf_get(rq_pages, &mqe->un.sli4_params); + sli4_params->rqe_size = bf_get(rqe_size, &mqe->un.sli4_params); + sli4_params->hdr_pages_max = bf_get(hdr_pages, &mqe->un.sli4_params); + sli4_params->hdr_size = bf_get(hdr_size, &mqe->un.sli4_params); + sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params); + sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params); + sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params); + + /* Make sure that sge_supp_len can be handled by the driver */ + if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE) + sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE; + + return rc; +} + +static uint32_t +lpfc_cgn_crc32(uint32_t crc, u8 byte) +{ + uint32_t msb = 0; + uint32_t bit; + + for (bit = 0; bit < 8; bit++) { + msb = (crc >> 31) & 1; + crc <<= 1; + + if (msb ^ (byte & 1)) { + crc ^= LPFC_CGN_CRC32_MAGIC_NUMBER; + crc |= 1; + } + byte >>= 1; + } + return crc; +} + +static uint32_t +lpfc_cgn_reverse_bits(uint32_t wd) +{ + uint32_t result = 0; + uint32_t i; + + for (i = 0; i < 32; i++) { + result <<= 1; + result |= (1 & (wd >> i)); + } + return result; +} + +/* + * The routine corresponds with the algorithm the HBA firmware + * uses to validate the data integrity. + */ +uint32_t +lpfc_cgn_calc_crc32(void *ptr, uint32_t byteLen, uint32_t crc) +{ + uint32_t i; + uint32_t result; + uint8_t *data = (uint8_t *)ptr; + + for (i = 0; i < byteLen; ++i) + crc = lpfc_cgn_crc32(crc, data[i]); + + result = ~lpfc_cgn_reverse_bits(crc); + return result; +} + +void +lpfc_init_congestion_buf(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct timespec64 cmpl_time; + struct tm broken; + uint16_t size; + uint32_t crc; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6235 INIT Congestion Buffer %px\n", phba->cgn_i); + + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + atomic_set(&phba->cgn_driver_evt_cnt, 0); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + phba->cgn_evt_minute = 0; + phba->hba_flag &= ~HBA_CGN_DAY_WRAP; + + memset(cp, 0xff, LPFC_CGN_DATA_SIZE); + cp->cgn_info_size = cpu_to_le16(LPFC_CGN_INFO_SZ); + cp->cgn_info_version = LPFC_CGN_INFO_V3; + + /* cgn parameters */ + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_acr = phba->cgn_p.cgn_param_acr; + cp->cgn_info_rxburst = phba->cgn_p.cgn_param_rxburst; + cp->cgn_info_rxbw = phba->cgn_p.cgn_param_rxbw; + + ktime_get_real_ts64(&cmpl_time); + time64_to_tm(cmpl_time.tv_sec, 0, &broken); + cp->cgn_info_month = broken.tm_mon + 1; + cp->cgn_info_day = broken.tm_mday; + cp->cgn_info_year = broken.tm_year - 100; /* relative to 2000 */ + cp->cgn_info_hour = broken.tm_hour; + cp->cgn_info_minute = broken.tm_min; + cp->cgn_info_second = broken.tm_sec; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "2643 CGNInfo Init: Start Time " + "%d/%d/%d %d:%d:%d\n", + cp->cgn_info_day, cp->cgn_info_month, + cp->cgn_info_year, cp->cgn_info_hour, + cp->cgn_info_minute, cp->cgn_info_second); + + /* Fill in default LUN qdepth */ + if (phba->pport) { + size = (uint16_t)(phba->pport->cfg_lun_queue_depth); + cp->cgn_lunq = cpu_to_le16(size); + } + + /* last used Index initialized to 0xff already */ + + cp->cgn_warn_freq = LPFC_FPIN_INIT_FREQ; + cp->cgn_alarm_freq = LPFC_FPIN_INIT_FREQ; + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + + phba->cgn_evt_timestamp = jiffies + + msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN); +} + +void +lpfc_init_congestion_stat(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct timespec64 cmpl_time; + struct tm broken; + uint32_t crc; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6236 INIT Congestion Stat %px\n", phba->cgn_i); + + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + memset(&cp->cgn_stat_npm, 0, LPFC_CGN_STAT_SIZE); + + ktime_get_real_ts64(&cmpl_time); + time64_to_tm(cmpl_time.tv_sec, 0, &broken); + cp->cgn_stat_month = broken.tm_mon + 1; + cp->cgn_stat_day = broken.tm_mday; + cp->cgn_stat_year = broken.tm_year - 100; /* relative to 2000 */ + cp->cgn_stat_hour = broken.tm_hour; + cp->cgn_stat_minute = broken.tm_min; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "2647 CGNstat Init: Start Time " + "%d/%d/%d %d:%d\n", + cp->cgn_stat_day, cp->cgn_stat_month, + cp->cgn_stat_year, cp->cgn_stat_hour, + cp->cgn_stat_minute); + + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); +} + +/** + * _lpfc_reg_congestion_buf - register congestion info buffer with HBA + * @phba: Pointer to hba context object. + * reg: flag to determine register or unregister. + */ +int +_lpfc_reg_congestion_buf(struct lpfc_hba *phba, int reg) +{ + struct lpfc_mbx_reg_congestion_buf *reg_congestion_buf; + union lpfc_sli4_cfg_shdr *shdr; + uint32_t shdr_status, shdr_add_status; + LPFC_MBOXQ_t *mboxq; + int length, rc; + + if (!phba->cgn_i) + return -ENXIO; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2641 REG_CONGESTION_BUF mbox allocation fail: " + "HBA state x%x reg %d\n", + phba->pport->port_state, reg); + return -ENOMEM; + } + + length = (sizeof(struct lpfc_mbx_reg_congestion_buf) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_REG_CONGESTION_BUF, length, + LPFC_SLI4_MBX_EMBED); + reg_congestion_buf = &mboxq->u.mqe.un.reg_congestion_buf; + bf_set(lpfc_mbx_reg_cgn_buf_type, reg_congestion_buf, 1); + if (reg > 0) + bf_set(lpfc_mbx_reg_cgn_buf_cnt, reg_congestion_buf, 1); + else + bf_set(lpfc_mbx_reg_cgn_buf_cnt, reg_congestion_buf, 0); + reg_congestion_buf->length = sizeof(struct lpfc_cgn_info); + reg_congestion_buf->addr_lo = + putPaddrLow(phba->cgn_i->phys); + reg_congestion_buf->addr_hi = + putPaddrHigh(phba->cgn_i->phys); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2642 REG_CONGESTION_BUF mailbox " + "failed with status x%x add_status x%x," + " mbx status x%x reg %d\n", + shdr_status, shdr_add_status, rc, reg); + return -ENXIO; + } + return 0; +} + +int +lpfc_unreg_congestion_buf(struct lpfc_hba *phba) +{ + lpfc_cmf_stop(phba); + return _lpfc_reg_congestion_buf(phba, 0); +} + +int +lpfc_reg_congestion_buf(struct lpfc_hba *phba) +{ + return _lpfc_reg_congestion_buf(phba, 1); +} + + /** * lpfc_get_sli4_parameters - Get the SLI4 Config PARAMETERS. * @phba: Pointer to HBA context object. * @mboxq: Pointer to the mailboxq memory for the mailbox command response. * * This function is called in the SLI4 code path to read the port's - * sli4 capabilities. + * sli4 capabilities. Called on proble from lpfc_sli4_driver_resource_setup. * * This function may be be called from any context that can block-wait * for the completion. The expectation is that this routine is called @@ -11604,8 +13870,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) else phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED; sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len; - sli4_params->loopbk_scope = bf_get(cfg_loopbk_scope, - mbx_sli4_parameters); + sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters); sli4_params->oas_supported = bf_get(cfg_oas, mbx_sli4_parameters); sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters); sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters); @@ -11615,6 +13880,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters); sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters); sli4_params->bv1s = bf_get(cfg_bv1s, mbx_sli4_parameters); + sli4_params->pls = bf_get(cfg_pvl, mbx_sli4_parameters); sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt, mbx_sli4_parameters); sli4_params->wqpcnt = bf_get(cfg_wqpcnt, mbx_sli4_parameters); @@ -11665,18 +13931,18 @@ fcponly: } } +#ifdef BUILD_NVME /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to - * accommodate 512K and 1M IOs in a single nvme buf and supply - * enough NVME LS iocb buffers for larger connectivity counts. + * accommodate 512K and 1M IOs in a single nvme buf. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - phba->cfg_iocb_cnt = 5; - } +#endif - /* Only embed PBDE for if_type 6, PBDE support requires xib be set */ - if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_6) || (!bf_get(cfg_xib, mbx_sli4_parameters))) + /* Enable embedded Payload BDE if support is indicated */ + if (bf_get(cfg_pbde, mbx_sli4_parameters)) + phba->cfg_enable_pbde = 1; + else phba->cfg_enable_pbde = 0; /* @@ -11737,7 +14003,6 @@ fcponly: phba->mds_diags_support = 1; else phba->mds_diags_support = 0; - /* * Check if the SLI port supports NSLER */ @@ -11746,6 +14011,13 @@ fcponly: else phba->nsler = 0; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) + INIT_LIST_HEAD(&phba->nvme_pendq); + INIT_LIST_HEAD(&phba->nvme_abts_pendq); + spin_lock_init(&phba->nvme_pendq_lock); + INIT_WORK(&phba->nvme_defer_work, lpfc_nvme_issue_pend_io); +#endif + phba->nvme_pendq_cnt = 0; return 0; } @@ -11766,7 +14038,7 @@ fcponly: * 0 - driver can claim the device * negative value - driver can not claim the device **/ -static int +static int __devinit lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) { struct lpfc_hba *phba; @@ -11790,6 +14062,9 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) if (error) goto out_disable_pci_dev; + phba->log.logit = true; /* Turn on throttle logs for Adapter */ + sprintf(phba->log.announcement, "adapter"); + /* Set up SLI-3 specific device PCI memory space */ error = lpfc_sli_pci_mem_setup(phba); if (error) { @@ -11806,6 +14081,9 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_unset_pci_mem_s3; } + /* no SCSI MQ support for SLI 3 */ + phba->cfg_enable_scsi_mq = 0; + /* Initialize and populate the iocb list per host */ error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT); @@ -11852,14 +14130,14 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0431 Failed to enable interrupt.\n"); error = -ENODEV; goto out_free_sysfs_attr; } /* SLI-3 HBA setup */ if (lpfc_sli_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1477 Failed to set up hba\n"); error = -ENODEV; goto out_remove_device; @@ -11926,7 +14204,7 @@ out_free_phba: * removed from PCI bus, it performs all the necessary cleanup for the HBA * device to be removed from the PCI subsystem properly. **/ -static void +static void __devexit lpfc_pci_remove_one_s3(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -11934,6 +14212,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) struct lpfc_vport **vports; struct lpfc_hba *phba = vport->phba; int i; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; @@ -11987,6 +14266,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) /* Disable interrupt */ lpfc_sli_disable_intr(phba); + pci_set_drvdata(pdev, NULL); scsi_host_put(shost); /* @@ -12011,7 +14291,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) lpfc_hba_free(phba); - pci_release_mem_regions(pdev); + pci_release_selected_regions(pdev, bars); pci_disable_device(pdev); } @@ -12117,7 +14397,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0430 PM resume Failed to enable interrupt\n"); return -EIO; } else @@ -12143,7 +14423,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) static void lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2723 PCI channel I/O abort preparing for recovery\n"); /* @@ -12164,7 +14444,7 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2710 PCI channel disable preparing for reset\n"); /* Block any management I/Os to the device */ @@ -12195,7 +14475,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) static void lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2711 PCI channel permanent disable for failure\n"); /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); @@ -12246,7 +14526,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_DISCONNECT; default: /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0472 Unknown PCI error state: x%x\n", state); lpfc_sli_prep_dev_for_reset(phba); return PCI_ERS_RESULT_NEED_RESET; @@ -12304,7 +14584,7 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0427 Cannot re-enable interrupt after " "slot reset.\n"); return PCI_ERS_RESULT_DISCONNECT; @@ -12340,6 +14620,14 @@ lpfc_io_resume_s3(struct pci_dev *pdev) /* Bring device online, it will be no-op for non-fatal error resume */ lpfc_online(phba); + + /* Clean up Advanced Error Reporting (AER) if needed */ + if (phba->hba_flag & HBA_AER_ENABLED) +#if defined(BUILD_SLES15SP2) || defined(BUILD_RHEL83) + pci_aer_clear_nonfatal_status(pdev); +#else + pci_cleanup_aer_uncorrect_error_status(pdev); +#endif } /** @@ -12389,35 +14677,57 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba) } -static void +static int lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize, const struct firmware *fw) { - if ((offset == ADD_STATUS_FW_NOT_SUPPORTED) || + int rc; + + /* Three cases: (1) FW was not supported on the detected adapter. + * (2) FW update has been locked out administratively. + * (3) Some other error during FW update. + * In each case, an unmaskable message is written to the console + * for admin diagnosis. + */ + if (offset == ADD_STATUS_FW_NOT_SUPPORTED || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && magic_number != MAGIC_NUMER_G6) || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC && - magic_number != MAGIC_NUMER_G7)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3030 This firmware version is not supported on " - "this HBA model. Device:%x Magic:%x Type:%x " - "ID:%x Size %d %zd\n", - phba->pcidev->device, magic_number, ftype, fid, - fsize, fw->size); - else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3022 FW Download failed. Device:%x Magic:%x Type:%x " - "ID:%x Size %d %zd\n", - phba->pcidev->device, magic_number, ftype, fid, - fsize, fw->size); + magic_number != MAGIC_NUMER_G7)) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3030 This firmware version is not supported on " + "this HBA model. Device:%x Magic:%x Type:%x " + "ID:%x Size %d %zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); + rc = -EINVAL; + } else if (offset == ADD_STATUS_FW_DOWNLOAD_HW_DISABLED) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3021 Firmware downloads have been prohibited " + "by a system configuration setting on " + "Device:%x Magic:%x Type:%x ID:%x Size %d " + "%zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); + rc = -EACCES; + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3022 FW Download failed. Add Status x%x " + "Device:%x Magic:%x Type:%x ID:%x Size %d " + "%zd\n", + offset, phba->pcidev->device, magic_number, + ftype, fid, fsize, fw->size); + rc = -EIO; + } + return rc; } - /** * lpfc_write_firmware - attempt to write a firmware image to the port * @fw: pointer to firmware image returned from request_firmware. - * @phba: pointer to lpfc hba data structure. + * @context: pointer to firmware image returned from request_firmware. + * @ret: return value this routine provides to the caller. * **/ static void @@ -12447,7 +14757,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) INIT_LIST_HEAD(&dma_buffer_list); lpfc_decode_firmware_rev(phba, fwrev, 1); if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3023 Updating Firmware, Current Version:%s " "New Version:%s\n", fwrev, image->revision); @@ -12486,14 +14796,18 @@ lpfc_write_firmware(const struct firmware *fw, void *context) rc = lpfc_wr_object(phba, &dma_buffer_list, (fw->size - offset), &offset); if (rc) { - lpfc_log_write_firmware_error(phba, offset, - magic_number, ftype, fid, fsize, fw); + rc = lpfc_log_write_firmware_error(phba, offset, + magic_number, + ftype, + fid, + fsize, + fw); goto release_out; } } rc = offset; } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3029 Skipped Firmware update, Current " "Version:%s New Version:%s\n", fwrev, image->revision); @@ -12507,9 +14821,12 @@ release_out: } release_firmware(fw); out: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3024 Firmware update done: %d.\n", rc); - return; + if (rc < 0) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3062 Firmware update error, status %d.\n", rc); + else + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3024 Firmware update success: size %d.\n", rc); } /** @@ -12533,6 +14850,11 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 13) + ret = request_firmware(&fw, file_name, &phba->pcidev->dev); + if (!ret) + lpfc_write_firmware(fw, (void *)phba); +#else if (fw_upgrade == INT_FW_UPGRADE) { ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, file_name, &phba->pcidev->dev, @@ -12545,6 +14867,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) } else { ret = -EINVAL; } +#endif return ret; } @@ -12567,7 +14890,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) * 0 - driver can claim the device * negative value - driver can not claim the device **/ -static int +static int __devinit lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) { struct lpfc_hba *phba; @@ -12591,6 +14914,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) if (error) goto out_disable_pci_dev; + phba->log.logit = true; /* Turn on throttle logs for Adapter */ + sprintf(phba->log.announcement, "adapter"); + /* Set up SLI-4 specific device PCI memory space */ error = lpfc_sli4_pci_mem_setup(phba); if (error) { @@ -12628,10 +14954,16 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) phba->pport = NULL; lpfc_stop_port(phba); + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); + + /* Init hba_eq_hdl array */ + lpfc_hba_eq_hdl_array_init(phba); + /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0426 Failed to enable interrupt.\n"); error = -ENODEV; goto out_unset_driver_resource; @@ -12666,7 +14998,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Set up SLI-4 HBA */ if (lpfc_sli4_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1421 Failed to set up hba\n"); error = -ENODEV; goto out_free_sysfs_attr; @@ -12691,7 +15023,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) */ error = lpfc_nvme_create_localport(vport); if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6004 NVME registration " "failed, error x%x\n", error); @@ -12710,6 +15042,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_sli4_ras_setup(phba); INIT_LIST_HEAD(&phba->poll_list); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + setup_timer(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, + (unsigned long)phba); +#else + timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); +#endif cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp); return 0; @@ -12744,7 +15082,7 @@ out_free_phba: * removed from PCI bus, it performs all the necessary cleanup for the HBA * device to be removed from the PCI subsystem properly. **/ -static void +static void __devexit lpfc_pci_remove_one_s4(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -12757,6 +15095,8 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); + if (phba->cgn_i) + lpfc_unreg_congestion_buf(phba); /* Free the HBA sysfs attributes */ lpfc_free_sysfs_attr(vport); @@ -12883,8 +15223,8 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) * state. * * Return code - * 0 - driver suspended the device - * Error otherwise + * 0 - driver resumed the device + * Error otherwise **/ static int lpfc_pci_resume_one_s4(struct pci_dev *pdev) @@ -12924,7 +15264,7 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0294 PM resume Failed to enable interrupt\n"); return -EIO; } else @@ -12950,7 +15290,7 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) static void lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2828 PCI channel I/O abort preparing for recovery\n"); /* * There may be errored I/Os through HBA, abort all I/Os on txcmplq @@ -12970,7 +15310,7 @@ lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2826 PCI channel disable preparing for reset\n"); /* Block any management I/Os to the device */ @@ -13002,7 +15342,7 @@ lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) static void lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2827 PCI channel permanent disable for failure\n"); /* Block all SCSI devices' I/Os on the host */ @@ -13052,7 +15392,7 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_DISCONNECT; default: /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2825 Unknown PCI error state: x%x\n", state); lpfc_sli4_prep_dev_for_reset(phba); return PCI_ERS_RESULT_NEED_RESET; @@ -13110,7 +15450,7 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2824 Cannot re-enable interrupt after " "slot reset.\n"); return PCI_ERS_RESULT_DISCONNECT; @@ -13153,6 +15493,14 @@ lpfc_io_resume_s4(struct pci_dev *pdev) /* Bring the device back online */ lpfc_online(phba); } + + /* Clean up Advanced Error Reporting (AER) if needed */ + if (phba->hba_flag & HBA_AER_ENABLED) +#if defined(BUILD_SLES15SP2) || defined(BUILD_RHEL83) + pci_aer_clear_nonfatal_status(pdev); +#else + pci_cleanup_aer_uncorrect_error_status(pdev); +#endif } /** @@ -13173,7 +15521,7 @@ lpfc_io_resume_s4(struct pci_dev *pdev) * 0 - driver can claim the device * negative value - driver can not claim the device **/ -static int +static int __devinit lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) { int rc; @@ -13201,7 +15549,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) * remove routine, which will perform all the necessary cleanup for the * device to be removed from the PCI subsystem properly. **/ -static void +static void __devexit lpfc_pci_remove_one(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -13215,7 +15563,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) lpfc_pci_remove_one_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1424 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13252,7 +15600,7 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) rc = lpfc_pci_suspend_one_s4(pdev, msg); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1425 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13288,7 +15636,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev) rc = lpfc_pci_resume_one_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1426 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13326,7 +15674,7 @@ lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) rc = lpfc_io_error_detected_s4(pdev, state); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1427 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13363,7 +15711,7 @@ lpfc_io_slot_reset(struct pci_dev *pdev) rc = lpfc_io_slot_reset_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1428 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13395,7 +15743,7 @@ lpfc_io_resume(struct pci_dev *pdev) lpfc_io_resume_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1429 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13403,6 +15751,36 @@ lpfc_io_resume(struct pci_dev *pdev) return; } +/** + * lpfc_mgmt_open - method called when 'lpfcmgmt' is opened from userspace + * @inode: pointer to the inode representing the lpfcmgmt device + * @filep: pointer to the file representing the open lpfcmgmt device + * + * This routine puts a reference count on the lpfc module whenever the + * character device is opened + **/ +static int +lpfc_mgmt_open(struct inode *inode, struct file *filep) +{ + try_module_get(THIS_MODULE); + return 0; +} + +/** + * lpfc_mgmt_release - method called when 'lpfcmgmt' is closed in userspace + * @inode: pointer to the inode representing the lpfcmgmt device + * @filep: pointer to the file representing the open lpfcmgmt device + * + * This routine removes a reference count from the lpfc module when the + * character device is closed + **/ +static int +lpfc_mgmt_release(struct inode *inode, struct file *filep) +{ + module_put(THIS_MODULE); + return 0; +} + /** * lpfc_sli4_oas_verify - Verify OAS is supported by this adapter * @phba: pointer to lpfc hba data structure. @@ -13458,9 +15836,74 @@ lpfc_sli4_ras_init(struct lpfc_hba *phba) } +/** + * lpfc_throttler - lpfc log throttling function + * @phba : the adapter instance. + * + * This routine is to be invoked by lpfc_throttle_log and lpfc_throttle_vlog. + * It is controlled using two module parameters. + * lpfc_throttle_log_time: The number of seconds to monitor the log count + * lpfc_throttle_log_cnt: The number of logs that cannot be exceeded within + * the throttle log time. + * + * This function acts as a gate to the logger. It monitors the the lpfc log + * load. If the log load exceeds the threshold, it return false which is a + * hint to the caller not to send the log. + * + * Return codes + * true - Okay to log + * false - Do not log + */ +bool +lpfc_throttler(struct lpfc_vport *vport, struct throttle_history *tlog) +{ + /* All times in microseconds */ + uint64_t now = (jiffies * ONE_SEC) / HZ; + struct lpfc_hba *phba = vport->phba; + + if (tlog->logit) { + /* Currently Logging */ + if (now > (tlog->log_start + + (phba->cfg_throttle_log_time * ONE_SEC))) { + /* Last Log more than one second ago */ + tlog->log_messages_lost = 0; + tlog->log_messages = 1; + tlog->log_start = now; + } + else if (++tlog->log_messages > phba->cfg_throttle_log_cnt) { + /* Transition to throttling */ + lpfc_printf_log(phba, KERN_INFO, LOG_EVENT, + "0040 Log compression on %s starting." + "\n", tlog->announcement); + tlog->log_messages_lost++; + tlog->log_messages = 0; + tlog->log_start = now; + tlog->logit = false; + } + + } else if (now > (tlog->log_start + + (300 * ONE_SEC))) { + /* Transition to logging if quiesced for five minutes */ + lpfc_printf_log(phba, KERN_INFO, LOG_EVENT, + "0041 Log compression %s ending, messages " + "have been quiesced with %d compressed.\n", + tlog->announcement, tlog->log_messages_lost); + + + tlog->log_start = now; + tlog->log_messages_lost = 0; + tlog->log_messages = 0; + tlog->logit = true; + } else { + /* Currently throttling */ + tlog->log_messages_lost++; + } + return tlog->logit; +} + MODULE_DEVICE_TABLE(pci, lpfc_id_table); -static const struct pci_error_handlers lpfc_err_handler = { +static struct pci_error_handlers lpfc_err_handler = { .error_detected = lpfc_io_error_detected, .slot_reset = lpfc_io_slot_reset, .resume = lpfc_io_resume, @@ -13470,20 +15913,20 @@ static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, - .remove = lpfc_pci_remove_one, - .shutdown = lpfc_pci_remove_one, + .remove = __devexit_p(lpfc_pci_remove_one), .suspend = lpfc_pci_suspend_one, .resume = lpfc_pci_resume_one, .err_handler = &lpfc_err_handler, }; static const struct file_operations lpfc_mgmt_fop = { - .owner = THIS_MODULE, + .open = lpfc_mgmt_open, + .release = lpfc_mgmt_release, }; static struct miscdevice lpfc_mgmt_dev = { .minor = MISC_DYNAMIC_MINOR, - .name = "lpfcmgmt", + .name = LPFCMGMT_NAME, .fops = &lpfc_mgmt_fop, }; @@ -13524,8 +15967,10 @@ lpfc_init(void) fc_release_transport(lpfc_transport_template); return -ENOMEM; } +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) lpfc_nvme_cmd_template(); lpfc_nvmet_cmd_template(); +#endif /* Initialize in case vector mapping is needed */ lpfc_present_cpu = num_present_cpus(); @@ -13552,6 +15997,84 @@ cpuhp_failure: return error; } +void lpfc_dmp_dbg(struct lpfc_hba *phba) +{ + unsigned int start_idx; + unsigned int dbg_cnt; + unsigned int temp_idx; + int i; + int j = 0; + unsigned long rem_nsec; + + if (phba->cfg_log_verbose) + return; + + if (atomic_cmpxchg(&phba->dbg_log_dmping, 0, 1) != 0) + return; + + start_idx = (unsigned int)atomic_read(&phba->dbg_log_idx) % DBG_LOG_SZ; + dbg_cnt = (unsigned int)atomic_read(&phba->dbg_log_cnt); + temp_idx = start_idx; + if (dbg_cnt >= DBG_LOG_SZ) { + dbg_cnt = DBG_LOG_SZ; + temp_idx -= 1; + } else { + if ((start_idx + dbg_cnt) > (DBG_LOG_SZ - 1)) { + temp_idx = (start_idx + dbg_cnt) % DBG_LOG_SZ; + } else { + if (start_idx < dbg_cnt) + start_idx = DBG_LOG_SZ - (dbg_cnt - start_idx); + else + start_idx -= dbg_cnt; + } + } + dev_info(&phba->pcidev->dev, "start %d end %d cnt %d\n", + start_idx, temp_idx, dbg_cnt); + + for (i = 0; i < dbg_cnt; i++) { + if ((start_idx + i) < DBG_LOG_SZ) + temp_idx = (start_idx + i) % DBG_LOG_SZ; + else + temp_idx = j++; + rem_nsec = do_div(phba->dbg_log[temp_idx].t_ns, NSEC_PER_SEC); + dev_info(&phba->pcidev->dev, "%d: [%5lu.%06lu] %s", + temp_idx, + (unsigned long)phba->dbg_log[temp_idx].t_ns, + rem_nsec / 1000, + phba->dbg_log[temp_idx].log); + } + atomic_set(&phba->dbg_log_cnt, 0); + atomic_set(&phba->dbg_log_dmping, 0); +} + +void lpfc_dbg_print(struct lpfc_hba *phba, const char *fmt, ...) +{ + unsigned int idx; + va_list args; + int dbg_dmping = atomic_read(&phba->dbg_log_dmping); + struct va_format vaf; + + + va_start(args, fmt); + if (unlikely(dbg_dmping)) { + vaf.fmt = fmt; + vaf.va = &args; + dev_info(&phba->pcidev->dev, "%pV", &vaf); + va_end(args); + return; + } + idx = (unsigned int)atomic_fetch_add(1, &phba->dbg_log_idx) % + DBG_LOG_SZ; + + atomic_inc(&phba->dbg_log_cnt); + + vscnprintf(phba->dbg_log[idx].log, + sizeof(phba->dbg_log[idx].log), fmt, args); + va_end(args); + + phba->dbg_log[idx].t_ns = local_clock(); +} + /** * lpfc_exit - lpfc module removal routine * @@ -13572,7 +16095,8 @@ lpfc_exit(void) module_init(lpfc_init); module_exit(lpfc_exit); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION(LPFC_MODULE_DESC); MODULE_AUTHOR("Broadcom"); MODULE_VERSION("0:" LPFC_DRIVER_VERSION); +MODULE_INFO(supported, "external"); diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index ea10f0343..c15acf654 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -44,13 +44,43 @@ #define LOG_NVME_DISC 0x00200000 /* NVME Discovery/Connect events. */ #define LOG_NVME_ABTS 0x00400000 /* NVME ABTS events. */ #define LOG_NVME_IOERR 0x00800000 /* NVME IO Error events. */ -#define LOG_ALL_MSG 0xffffffff /* LOG all messages */ +#define LOG_EDIF 0x01000000 /* External DIF events */ +#define LOG_AUTH 0x02000000 /* Authentication events */ +#define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */ +#define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */ +#define LOG_ALL_MSG 0x7fffffff /* LOG all messages */ + +void lpfc_dmp_dbg(struct lpfc_hba *phba); +void lpfc_dbg_print(struct lpfc_hba *phba, const char *fmt, ...); + +/* generate message by verbose log setting or severity */ +#define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \ +{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '4')) \ + dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } + +#define lpfc_log_msg(phba, level, mask, fmt, arg...) \ +do { \ + { uint32_t log_verbose = (phba)->pport ? \ + (phba)->pport->cfg_log_verbose : \ + (phba)->cfg_log_verbose; \ + if (((mask) & log_verbose) || (level[1] <= '4')) \ + dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ + fmt, phba->brd_no, ##arg); \ + } \ +} while (0) #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ do { \ - { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \ + { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) { \ + if ((mask) & LOG_TRACE_EVENT) \ + lpfc_dmp_dbg((vport)->phba); \ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ - fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \ + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); \ + } else if (!(vport)->cfg_log_verbose) \ + lpfc_dbg_print((vport)->phba, "%d:(%d):" fmt, \ + (vport)->phba->brd_no, (vport)->vpi, ##arg); \ + } \ } while (0) #define lpfc_printf_log(phba, level, mask, fmt, arg...) \ @@ -58,8 +88,52 @@ do { \ { uint32_t log_verbose = (phba)->pport ? \ (phba)->pport->cfg_log_verbose : \ (phba)->cfg_log_verbose; \ - if (((mask) & log_verbose) || (level[1] <= '3')) \ + if (((mask) & log_verbose) || (level[1] <= '3')) { \ + if ((mask) & LOG_TRACE_EVENT) \ + lpfc_dmp_dbg(phba); \ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ - fmt, phba->brd_no, ##arg); \ + fmt, phba->brd_no, ##arg); \ + } else if (!(phba)->cfg_log_verbose)\ + lpfc_dbg_print(phba, "%d:" fmt, phba->brd_no, ##arg); \ } \ } while (0) + +#define lpfc_throttle_vlog(vport, hist, log, fmt, arg...) \ +do { \ + { if (!lpfc_throttler(vport, (hist))) \ + break; \ + lpfc_printf_vlog(vport, KERN_INFO, log, \ + fmt, arg); \ + }\ +} while (0) + +#define lpfc_throttle_log(phba, hist, log, fmt, arg...) \ +do { \ + { if (!lpfc_throttler((phba->pport), (hist))) \ + break; \ + lpfc_printf_log(phba, KERN_INFO, log, \ + fmt, arg); \ + }\ +} while (0) + +#define lpfc_optioned_vlog(vport, hist, level, mask, fmt, arg...) \ +do { \ + { if (!lpfc_throttler(vport, (hist))) \ + { lpfc_printf_vlog(vport, level, mask, fmt, ##arg); \ + break; \ + }\ + dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); \ + }\ +} while (0) + +#define lpfc_optioned_log(phba, hist, level, mask, fmt, arg...) \ +do { \ + { if (!lpfc_throttler((phba->pport), (hist))) \ + { lpfc_printf_log(phba, level, mask, fmt, ##arg); \ + break; \ + }\ + dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ + fmt, phba->brd_no, ##arg); \ + }\ +} while (0) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 4a3311640..d2ce919cc 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -515,6 +515,7 @@ lpfc_init_link(struct lpfc_hba * phba, if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && + !(phba->sli4_hba.pc_sli4_params.pls) && mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) { mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT; @@ -755,7 +756,6 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, struct lpfc_dmabuf *mp; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->un.varRegLogin.rpi = 0; if (phba->sli_rev == LPFC_SLI_REV4) mb->un.varRegLogin.rpi = phba->sli4_hba.rpi_ids[rpi]; @@ -1296,10 +1296,8 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* If HBA supports SLI=3 ask for it */ if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) { - if (phba->cfg_enable_bg) + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */ - if (phba->cfg_enable_dss) - mb->un.varCfgPort.cdss = 1; /* Configure Security */ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); @@ -1379,7 +1377,8 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) */ if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { - phba->host_gp = &phba->mbox->us.s2.host[0]; + phba->host_gp = (struct lpfc_hgp __iomem *) + &phba->mbox->us.s2.host[0]; phba->hbq_put = NULL; offset = (uint8_t *)&phba->mbox->us.s2.host - (uint8_t *)phba->slim2p.virt; @@ -2085,7 +2084,7 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) bf_set(lpfc_mbx_rq_ftr_rq_perfh, &mboxq->u.mqe.un.req_ftrs, 1); /* Enable DIF (block guard) only if configured to do so. */ - if (phba->cfg_enable_bg) + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1); /* Enable NPIV only if configured to do so. */ @@ -2299,7 +2298,7 @@ lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox) return 0; } -static void +void lpfc_mbx_cmpl_rdp_link_stat(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { MAILBOX_t *mb; @@ -2320,7 +2319,7 @@ mbx_failed: rdp_context->cmpl(phba, rdp_context, rc); } -static void +void lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) { struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)mbox->ctx_buf; @@ -2367,7 +2366,7 @@ lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) goto error; lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a0, - DMP_SFF_PAGE_A0_SIZE); + DMP_SFF_PAGE_A0_SIZE); memset(mbox, 0, sizeof(*mbox)); @@ -2380,13 +2379,13 @@ lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_DUMP_MEMORY); bf_set(lpfc_mbx_memory_dump_type3_type, - &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); + &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); bf_set(lpfc_mbx_memory_dump_type3_link, - &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port); + &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port); bf_set(lpfc_mbx_memory_dump_type3_page_no, - &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A2); + &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A2); bf_set(lpfc_mbx_memory_dump_type3_length, - &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A2_SIZE); + &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A2_SIZE); mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys); mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys); @@ -2439,13 +2438,13 @@ lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox) mbox->ctx_buf = mp; bf_set(lpfc_mbx_memory_dump_type3_type, - &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); + &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); bf_set(lpfc_mbx_memory_dump_type3_link, - &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port); + &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port); bf_set(lpfc_mbx_memory_dump_type3_page_no, - &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A0); + &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A0); bf_set(lpfc_mbx_memory_dump_type3_length, - &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE); + &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE); mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys); mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys); @@ -2622,3 +2621,39 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp) resume_rpi->event_tag = ndlp->phba->fc_eventTag; } +/** + * lpfc_supported_pages - Initialize the PORT_CAPABILITIES supported pages + * mailbox command. + * @mbox: pointer to lpfc mbox command to initialize. + * + * The PORT_CAPABILITIES supported pages mailbox command is issued to + * retrieve the particular feature pages supported by the port. + **/ +void +lpfc_supported_pages(struct lpfcMboxq *mbox) +{ + struct lpfc_mbx_supp_pages *supp_pages; + + memset(mbox, 0, sizeof(*mbox)); + supp_pages = &mbox->u.mqe.un.supp_pages; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); + bf_set(cpn, supp_pages, LPFC_SUPP_PAGES); +} + +/** + * lpfc_pc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params mbox cmd. + * @mbox: pointer to lpfc mbox command to initialize. + * + * The PORT_CAPABILITIES SLI4 parameters mailbox command is issued to + * retrieve the particular SLI4 features supported by the port. + **/ +void +lpfc_pc_sli4_params(struct lpfcMboxq *mbox) +{ + struct lpfc_mbx_pc_sli4_params *sli4_params; + + memset(mbox, 0, sizeof(*mbox)); + sli4_params = &mbox->u.mqe.un.sli4_params; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); + bf_set(cpn, sli4_params, LPFC_SLI4_PARAMETERS); +} diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ef75fd6c0..2e9a6a6bd 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -30,9 +30,11 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include - +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -49,6 +51,8 @@ #define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ #define LPFC_DEVICE_DATA_POOL_SIZE 64 /* max elements in device data pool */ +#define LPFC_RRQ_POOL_SIZE 256 /* max elements in non-DMA pool */ +#define LPFC_MBX_POOL_SIZE 256 /* max elements in MBX non-DMA pool */ int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { @@ -89,16 +93,14 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; int i; - phba->lpfc_mbuf_pool = dma_pool_create("lpfc_mbuf_pool", &phba->pcidev->dev, LPFC_BPL_SIZE, align, 0); if (!phba->lpfc_mbuf_pool) goto fail; - pool->elements = kmalloc_array(LPFC_MBUF_POOL_SIZE, - sizeof(struct lpfc_dmabuf), - GFP_KERNEL); + pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) * + LPFC_MBUF_POOL_SIZE, GFP_KERNEL); if (!pool->elements) goto fail_free_lpfc_mbuf_pool; @@ -113,8 +115,8 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) pool->current_count++; } - phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(LPFC_MBOXQ_t)); + phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MBX_POOL_SIZE, + sizeof(LPFC_MBOXQ_t)); if (!phba->mbox_mem_pool) goto fail_free_mbuf_pool; @@ -125,7 +127,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) if (phba->sli_rev == LPFC_SLI_REV4) { phba->rrq_pool = - mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, + mempool_create_kmalloc_pool(LPFC_RRQ_POOL_SIZE, sizeof(struct lpfc_node_rrq)); if (!phba->rrq_pool) goto fail_free_nlp_mem_pool; @@ -230,9 +232,6 @@ lpfc_mem_free(struct lpfc_hba *phba) dma_pool_destroy(phba->lpfc_hrb_pool); phba->lpfc_hrb_pool = NULL; - dma_pool_destroy(phba->txrdy_payload_pool); - phba->txrdy_payload_pool = NULL; - dma_pool_destroy(phba->lpfc_hbq_pool); phba->lpfc_hbq_pool = NULL; @@ -240,7 +239,8 @@ lpfc_mem_free(struct lpfc_hba *phba) phba->rrq_pool = NULL; /* Free NLP memory pool */ - mempool_destroy(phba->nlp_mem_pool); + if (phba->nlp_mem_pool) + mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) { mempool_destroy(phba->active_rrq_pool); @@ -248,7 +248,8 @@ lpfc_mem_free(struct lpfc_hba *phba) } /* Free mbox memory pool */ - mempool_destroy(phba->mbox_mem_pool); + if (phba->mbox_mem_pool) + mempool_destroy(phba->mbox_mem_pool); phba->mbox_mem_pool = NULL; /* Free MBUF memory pool */ @@ -339,6 +340,19 @@ lpfc_mem_free_all(struct lpfc_hba *phba) dma_pool_destroy(phba->lpfc_cmd_rsp_buf_pool); phba->lpfc_cmd_rsp_buf_pool = NULL; + /* Free Congestion Data buffer */ + if (phba->cgn_i) { + dma_free_coherent(&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + phba->cgn_i->virt, phba->cgn_i->phys); + kfree(phba->cgn_i); + phba->cgn_i = NULL; + } + + /* Free RX table */ + kfree(phba->rxtable); + phba->rxtable = NULL; + /* Free the iocb lookup array */ kfree(psli->iocbq_lookup); psli->iocbq_lookup = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h index 95d60ab5e..09db13aca 100644 --- a/drivers/scsi/lpfc/lpfc_nl.h +++ b/drivers/scsi/lpfc/lpfc_nl.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index fdd87508c..444329b4d 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -31,8 +31,11 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -154,7 +157,7 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name)); return 1; bad_service_param: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0207 Device %x " "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent " "invalid service parameters. Ignoring device.\n", @@ -252,6 +255,8 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_sli_issue_abort_iotag(phba, pring, iocb); spin_unlock_irq(&phba->hbalock); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); INIT_LIST_HEAD(&abort_list); @@ -286,7 +291,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * This routine is only called if we are SLI3, direct connect pt2pt * mode and the remote NPort issues the PLOGI after link up. */ -static void +void lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) { LPFC_MBOXQ_t *login_mbox; @@ -303,7 +308,7 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) /* Check for CONFIG_LINK error */ if (mb->mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4575 CONFIG_LINK fails pt2pt discovery: %x\n", mb->mbxStatus); mempool_free(login_mbox, phba->mbox_mem_pool); @@ -318,7 +323,7 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) rc = lpfc_els_rsp_acc(link_mbox->vport, ELS_CMD_PLOGI, save_iocb, ndlp, login_mbox); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4576 PLOGI ACC fails pt2pt discovery: %x\n", rc); mempool_free(login_mbox, phba->mbox_mem_pool); @@ -340,7 +345,7 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) * This routine is only called if we are SLI4, acting in target * mode and the remote NPort issues the PLOGI after link up. **/ -static void +void lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; @@ -363,7 +368,7 @@ lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_sli4_unreg_rpi_cmpl_clr(phba, pmb); if (!piocb) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4578 PLOGI ACC fail\n"); if (mbox) mempool_free(mbox, phba->mbox_mem_pool); @@ -372,7 +377,7 @@ lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, piocb, ndlp, mbox); if (rc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4579 PLOGI ACC fail %x\n", rc); if (mbox) mempool_free(mbox, phba->mbox_mem_pool); @@ -407,7 +412,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lp = (uint32_t *) pcmd->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); if (wwn_to_u64(sp->portName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0140 PLOGI Reject: invalid nname\n"); stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; @@ -416,7 +421,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; } if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0141 PLOGI Reject: invalid pname\n"); stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; @@ -477,13 +482,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_type & NLP_FABRIC) && !(phba->nvmet_support)) { + /* Clear ndlp info, since follow up PRLI may have + * updated ndlp information + */ + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; + ndlp->nlp_flag &= ~NLP_FIRSTBURST; + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); return 1; } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0143 PLOGI recv'd from DID: x%x " "WWPN changed: old %llx new %llx\n", ndlp->nlp_DID, @@ -500,6 +514,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; ndlp->nlp_flag &= ~NLP_FIRSTBURST; login_mbox = NULL; @@ -686,7 +701,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; out: if (defer_acc) - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4577 discovery failure: %p %p %p\n", save_iocb, link_mbox, login_mbox); kfree(save_iocb); @@ -794,11 +809,17 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp, NULL); } out: - /* If we are authenticated, move to the proper state */ - if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) - lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - else - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + /* If we are authenticated, move to the proper state. + * It is possible an ADISC arrived and the remote nport + * is already in MAPPED or UNMAPPED state. Catch this + * condition and don't set the nlp_state again because + * it causes an unnecessary transport unregister/register. + */ + if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) { + if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_MAPPED_NODE); + } return 1; } @@ -888,14 +909,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } } else if ((!(ndlp->nlp_type & NLP_FABRIC) && ((ndlp->nlp_type & NLP_FCP_TARGET) || - (ndlp->nlp_type & NLP_NVME_TARGET) || - (vport->fc_flag & FC_PT2PT))) || + !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { - /* Only try to re-login if this is NOT a Fabric Node - * AND the remote NPORT is a FCP/NVME Target or we - * are in pt2pt mode. NLP_STE_ADISC_ISSUE is a special - * case for LOGO as a response to ADISC behavior. - */ + /* Only try to re-login if this is NOT a Fabric Node */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); spin_lock_irq(shost->host_lock); @@ -976,6 +992,7 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type |= NLP_FCP_INITIATOR; if (npr->prliType == PRLI_NVME_TYPE) ndlp->nlp_type |= NLP_NVME_INITIATOR; + ndlp->nlp_flag &= ~NLP_EXTERNAL_DIF; } if (npr->targetFunc) { if (npr->prliType == PRLI_FCP_TYPE) @@ -1037,9 +1054,9 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!(vport->fc_flag & FC_PT2PT)) { /* Check config parameter use-adisc or FCP-2 */ - if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || + if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && - (ndlp->nlp_type & NLP_FCP_TARGET)))) { + (ndlp->nlp_type & NLP_FCP_TARGET))) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(shost->host_lock); @@ -1087,8 +1104,8 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2796 mailbox memory allocation failed \n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2796 mailbox memory allocation failed \n"); else { lpfc_unreg_login(phba, vport->vpi, rpi, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -1126,7 +1143,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, ndlp, rpi); } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0271 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, @@ -1144,11 +1161,11 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * to stop it. */ if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0272 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", - ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, - ndlp->nlp_flag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0272 Illegal State Transition: node x%x " + "event x%x, state x%x Data: x%x x%x\n", + ndlp->nlp_DID, evt, ndlp->nlp_state, + ndlp->nlp_rpi, ndlp->nlp_flag); } return ndlp->nlp_state; } @@ -1368,7 +1385,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, if ((ndlp->nlp_DID != FDMI_DID) && (wwn_to_u64(sp->portName.u.wwn) == 0 || wwn_to_u64(sp->nodeName.u.wwn) == 0)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0142 PLOGI RSP: Invalid WWN.\n"); goto out; } @@ -1430,7 +1447,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, } else { mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0133 PLOGI: no memory " "for config_link " "Data: x%x x%x x%x x%x\n", @@ -1455,7 +1473,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0018 PLOGI: no memory for reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1495,7 +1513,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, kfree(mp); mempool_free(mbox, phba->mbox_mem_pool); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0134 PLOGI: cannot issue reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1503,7 +1521,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, } else { mempool_free(mbox, phba->mbox_mem_pool); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0135 PLOGI: cannot format reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1514,7 +1532,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, out: if (ndlp->nlp_DID == NameServer_DID) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0261 Cannot Register NameServer login\n"); } @@ -1733,7 +1751,13 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, } } - if (ndlp->nlp_type & NLP_FCP_TARGET) { + if (ndlp->nlp_type & NLP_FCP_TARGET) + ndlp->nlp_fc4_type |= NLP_FC4_FCP; + + if (ndlp->nlp_type & NLP_NVME_TARGET) + ndlp->nlp_fc4_type |= NLP_FC4_NVME; + + if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) { ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); } else { @@ -1936,8 +1960,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, if (mb->mbxStatus) { /* RegLogin failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0246 RegLogin failed Data: x%x x%x x%x x%x " + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0246 RegLogin failed Data: x%x x%x x%x x%x " "x%x\n", did, mb->mbxStatus, vport->port_state, mb->un.varRegLogin.vpi, @@ -1961,6 +1985,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -2018,8 +2044,10 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); } } else { +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) if ((vport->fc_flag & FC_PT2PT) && phba->nvmet_support) phba->targetport->port_id = vport->fc_myDID; +#endif /* Only Fabric ports should transition. NVME target * must complete PRLI. @@ -2102,6 +2130,7 @@ lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) return ndlp->nlp_state; + lpfc_rcv_prli(vport, ndlp, cmdiocb); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; } @@ -2154,7 +2183,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, IOCB_t *irsp; PRLI *npr; struct lpfc_nvme_prli *nvpr; + struct lpfc_scsi_io_req cmd_req; void *temp_ptr; + int ret = 0; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; @@ -2194,16 +2225,28 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "6028 FCP NPR PRLI Cmpl Init %d Target %d\n", npr->initiatorFunc, npr->targetFunc); - if (npr->initiatorFunc) + + if (npr->initiatorFunc) { ndlp->nlp_type |= NLP_FCP_INITIATOR; + ndlp->nlp_flag &= ~NLP_EXTERNAL_DIF; + } if (npr->targetFunc) { ndlp->nlp_type |= NLP_FCP_TARGET; - if (npr->writeXferRdyDis) + if (npr->writeXferRdyDis) { ndlp->nlp_flag |= NLP_FIRSTBURST; + cmd_req.cmd_id = MODE_SENSE; + cmd_req.dev_id = CTRL_ID; + cmd_req.cmd_cmpl = lpfc_mode_sense_cmpl; + ret = lpfc_issue_scsi_cmd(vport, ndlp, + &cmd_req); + lpfc_printf_vlog(vport, KERN_INFO, + LOG_FCP | LOG_FCP_ERROR, + "6334 FB issue returns %d\n", + ret); + } } if (npr->Retry) ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; - } else if (nvpr && (bf_get_be32(prli_acc_rsp_code, nvpr) == PRLI_REQ_EXECUTED) && @@ -2214,7 +2257,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (bf_get_be32(prli_init, nvpr)) ndlp->nlp_type |= NLP_NVME_INITIATOR; - if (phba->nsler && bf_get_be32(prli_nsler, nvpr)) + if (phba->nsler && bf_get_be32(prli_nsler, nvpr) && + bf_get_be32(prli_conf, nvpr)) + ndlp->nlp_nvme_info |= NLP_NVME_NSLER; else ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 5a86a1ee0..70257b6eb 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -35,10 +35,14 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include #include #include +#define BUILD_NVME_FC +#endif +#endif #include "lpfc_version.h" #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -55,13 +59,24 @@ #include "lpfc_debugfs.h" /* NVME initiator-based functions */ - +#ifdef BUILD_NVME_FC static struct lpfc_io_buf * lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int idx, int expedite); static void lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_io_buf *); +static void +lpfc_nvme_complete_pend_io(struct lpfc_hba *, + struct nvmefc_fcp_req *); +static void +lpfc_nvme_insert_pend_io(struct lpfc_hba *, + struct nvmefc_fcp_req *, + struct nvme_fc_local_port *, + struct nvme_fc_remote_port *, + void *, + u32 to_head); + static struct nvme_fc_port_template lpfc_nvme_template; @@ -195,6 +210,46 @@ lpfc_nvme_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } +/** + * lpfc_nvme_prep_abort_wqe - set up 'abort' work queue entry. + * @pwqeq: Pointer to command iocb. + * @xritag: Tag that uniqely identifies the local exchange resource. + * @opt: Option bits - + * bit 0 = inhibit sending abts on the link + * + * This function is called with hbalock held. + **/ +void +lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt) +{ + union lpfc_wqe128 *wqe = &pwqeq->wqe; + + /* WQEs are reused. Clear stale data and set key fields to + * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. + */ + memset(wqe, 0, sizeof(*wqe)); + + if (opt & INHIBIT_ABORT) + bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); + /* Abort specified xri tag, with the mask deliberately zeroed */ + bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); + + bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + + /* Abort the IO associated with this outstanding exchange ID. */ + wqe->abort_cmd.wqe_com.abort_tag = xritag; + + /* iotag for the wqe completion. */ + bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag); + + bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + + bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); + bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); +} + /** * lpfc_nvme_create_queue - * @lpfc_pnvme: Pointer to the driver's nvme instance data @@ -245,6 +300,10 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, qhandle->index = qidx; } + spin_lock(&lport->qhandle_list_lock); + list_add(&qhandle->list, &lport->qhandle_list); + spin_unlock(&lport->qhandle_list_lock); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, "6073 Binding %s HdwQueue %d (cpu %d) to " "hdw_queue %d qhandle x%px\n", str, @@ -274,6 +333,9 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport, { struct lpfc_nvme_lport *lport; struct lpfc_vport *vport; + struct lpfc_nvme_qhandle *qhandle; + struct lpfc_nvme_qhandle *tmp; + bool found = false; if (!pnvme_lport->private) return; @@ -284,9 +346,29 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport, lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, "6001 ENTER. lpfc_pnvme x%px, qidx x%x qhandle x%px\n", lport, qidx, handle); - kfree(handle); -} + /* Protect against double-free errors from misbehaved upper layers */ + if (handle) { + qhandle = (struct lpfc_nvme_qhandle *)handle; + /* Search if on active list */ + spin_lock(&lport->qhandle_list_lock); + list_for_each_entry(tmp, &lport->qhandle_list, list) { + if (tmp == qhandle) { + list_del_init(&tmp->list); + kfree(qhandle); + found = true; + break; + } + } + spin_unlock(&lport->qhandle_list_lock); + } + + if (!found) + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME, + "6568 Invalid qhandle ptr to free " + "lpfc_pnvme x%p, qidx x%x, qhandle x%p\n", + lport, qidx, handle); +} static void lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport) { @@ -336,7 +418,7 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) remoteport); spin_lock_irq(&vport->phba->hbalock); - /* The register rebind might have occurred before the delete + /* The register rebind might have occured before the delete * downcall. Guard against this race. */ if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) { @@ -404,7 +486,7 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if (pnvme_lsreq->done) pnvme_lsreq->done(pnvme_lsreq, status); else - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6046 nvme cmpl without done call back? " "Data %px DID %x Xri: %x status %x\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, @@ -535,7 +617,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, rc = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], genwqe); if (rc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6045 Issue GEN REQ WQE to NPORT x%x " "Data: x%x x%x\n", ndlp->nlp_DID, genwqe->iotag, @@ -571,7 +653,6 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nodelist *ndlp; struct ulp_bde64 *bpl; struct lpfc_dmabuf *bmp; - uint16_t ntype, nstate; /* there are two dma buf in the request, actually there is one and * the second one is just the start address + cmd size. @@ -597,7 +678,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, /* Need the ndlp. It is stored in the driver's rport. */ ndlp = rport->ndlp; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6051 Remoteport x%px, rport has invalid ndlp. " "Failing LS Req\n", pnvme_rport); return -ENODEV; @@ -606,11 +687,11 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, /* The remote node has to be a mapped nvme target or an * unmapped nvme initiator or it's an error. */ - ntype = ndlp->nlp_type; - nstate = ndlp->nlp_state; - if ((ntype & NLP_NVME_TARGET && nstate != NLP_STE_MAPPED_NODE) || - (ntype & NLP_NVME_INITIATOR && nstate != NLP_STE_UNMAPPED_NODE)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, + if (((ndlp->nlp_type & NLP_NVME_TARGET) && + (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) || + ((ndlp->nlp_type & NLP_NVME_INITIATOR) && + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6088 DID x%06x not ready for " "IO. State x%x, Type x%x\n", pnvme_rport->port_id, @@ -620,7 +701,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!bmp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6044 Could not find node for DID %x\n", pnvme_rport->port_id); return 2; @@ -628,7 +709,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, INIT_LIST_HEAD(&bmp->list); bmp->virt = lpfc_mbuf_alloc(vport->phba, MEM_PRI, &(bmp->phys)); if (!bmp->virt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6042 Could not find node for DID %x\n", pnvme_rport->port_id); kfree(bmp); @@ -668,7 +749,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, ndlp, 2, 30, 0); if (ret != WQE_SUCCESS) { atomic_inc(&lport->xmt_ls_err); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6052 EXIT. issue ls wqe failed lport x%px, " "rport x%px lsreq x%px Status %x DID %x\n", pnvme_lport, pnvme_rport, pnvme_lsreq, @@ -719,7 +800,7 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); if (!ndlp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6049 Could not find node for DID %x\n", pnvme_rport->port_id); return; @@ -760,6 +841,10 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, lpfc_sli_issue_abort_iotag(phba, pring, wqe); spin_unlock_irq(&phba->hbalock); } + + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + } /* Fix up the existing sgls for NVME IO. */ @@ -859,89 +944,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport, sgl->sge_len = cpu_to_le32(nCmd->rsplen); } -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -static void -lpfc_nvme_ktime(struct lpfc_hba *phba, - struct lpfc_io_buf *lpfc_ncmd) -{ - uint64_t seg1, seg2, seg3, seg4; - uint64_t segsum; - - if (!lpfc_ncmd->ts_last_cmd || - !lpfc_ncmd->ts_cmd_start || - !lpfc_ncmd->ts_cmd_wqput || - !lpfc_ncmd->ts_isr_cmpl || - !lpfc_ncmd->ts_data_nvme) - return; - - if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_cmd_start) - return; - if (lpfc_ncmd->ts_cmd_start < lpfc_ncmd->ts_last_cmd) - return; - if (lpfc_ncmd->ts_cmd_wqput < lpfc_ncmd->ts_cmd_start) - return; - if (lpfc_ncmd->ts_isr_cmpl < lpfc_ncmd->ts_cmd_wqput) - return; - if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_isr_cmpl) - return; - /* - * Segment 1 - Time from Last FCP command cmpl is handed - * off to NVME Layer to start of next command. - * Segment 2 - Time from Driver receives a IO cmd start - * from NVME Layer to WQ put is done on IO cmd. - * Segment 3 - Time from Driver WQ put is done on IO cmd - * to MSI-X ISR for IO cmpl. - * Segment 4 - Time from MSI-X ISR for IO cmpl to when - * cmpl is handled off to the NVME Layer. - */ - seg1 = lpfc_ncmd->ts_cmd_start - lpfc_ncmd->ts_last_cmd; - if (seg1 > 5000000) /* 5 ms - for sequential IOs only */ - seg1 = 0; - - /* Calculate times relative to start of IO */ - seg2 = (lpfc_ncmd->ts_cmd_wqput - lpfc_ncmd->ts_cmd_start); - segsum = seg2; - seg3 = lpfc_ncmd->ts_isr_cmpl - lpfc_ncmd->ts_cmd_start; - if (segsum > seg3) - return; - seg3 -= segsum; - segsum += seg3; - - seg4 = lpfc_ncmd->ts_data_nvme - lpfc_ncmd->ts_cmd_start; - if (segsum > seg4) - return; - seg4 -= segsum; - - phba->ktime_data_samples++; - phba->ktime_seg1_total += seg1; - if (seg1 < phba->ktime_seg1_min) - phba->ktime_seg1_min = seg1; - else if (seg1 > phba->ktime_seg1_max) - phba->ktime_seg1_max = seg1; - phba->ktime_seg2_total += seg2; - if (seg2 < phba->ktime_seg2_min) - phba->ktime_seg2_min = seg2; - else if (seg2 > phba->ktime_seg2_max) - phba->ktime_seg2_max = seg2; - phba->ktime_seg3_total += seg3; - if (seg3 < phba->ktime_seg3_min) - phba->ktime_seg3_min = seg3; - else if (seg3 > phba->ktime_seg3_max) - phba->ktime_seg3_max = seg3; - phba->ktime_seg4_total += seg4; - if (seg4 < phba->ktime_seg4_min) - phba->ktime_seg4_min = seg4; - else if (seg4 > phba->ktime_seg4_max) - phba->ktime_seg4_max = seg4; - - lpfc_ncmd->ts_last_cmd = 0; - lpfc_ncmd->ts_cmd_start = 0; - lpfc_ncmd->ts_cmd_wqput = 0; - lpfc_ncmd->ts_isr_cmpl = 0; - lpfc_ncmd->ts_data_nvme = 0; -} -#endif - /** * lpfc_nvme_io_cmd_wqe_cmpl - Complete an NVME-over-FCP IO * @lpfc_pnvme: Pointer to the driver's nvme instance data @@ -972,11 +974,15 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, uint32_t code, status, idx; uint16_t cid, sqhd, data; uint32_t *ptr; + uint32_t lat; + bool call_done = false; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + int cpu; +#endif /* Sanity check on return of outstanding command */ if (!lpfc_ncmd) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_NODE | LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6071 Null lpfc_ncmd pointer. No " "release, skip completion\n"); return; @@ -987,7 +993,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, if (!lpfc_ncmd->nvmeCmd) { spin_unlock(&lpfc_ncmd->buf_lock); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6066 Missing cmpl ptrs: lpfc_ncmd x%px, " "nvmeCmd x%px\n", lpfc_ncmd, lpfc_ncmd->nvmeCmd); @@ -1014,13 +1020,14 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, lpfc_nvmeio_data(phba, "NVME FCP CMPL: xri x%x stat x%x parm x%x\n", lpfc_ncmd->cur_iocbq.sli4_xritag, status, wcqe->parameter); + /* * Catch race where our node has transitioned, but the * transport is still transitioning. */ ndlp = lpfc_ncmd->ndlp; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6062 Ignoring NVME cmpl. No ndlp\n"); goto out_err; } @@ -1091,7 +1098,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, /* Sanity check */ if (nCmd->rcv_rsplen == LPFC_NVME_ERSP_LEN) break; - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6081 NVME Completion Protocol Error: " "xri %x status x%x result x%x " "placed x%x\n", @@ -1140,38 +1147,44 @@ out_err: #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (lpfc_ncmd->ts_cmd_start) { lpfc_ncmd->ts_isr_cmpl = pwqeIn->isr_timestamp; - lpfc_ncmd->ts_data_nvme = ktime_get_ns(); - phba->ktime_last_cmd = lpfc_ncmd->ts_data_nvme; - lpfc_nvme_ktime(phba, lpfc_ncmd); + lpfc_ncmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_ncmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_ncmd); } - if (unlikely(phba->cpucheck_on & LPFC_CHECK_NVME_IO)) { - uint32_t cpu; - idx = lpfc_ncmd->cur_iocbq.hba_wqidx; + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_NVME_IO)) { cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - if (lpfc_ncmd->cpu != cpu) - lpfc_printf_vlog(vport, - KERN_INFO, LOG_NVME_IOERR, - "6701 CPU Check cmpl: " - "cpu %d expect %d\n", - cpu, lpfc_ncmd->cpu); - phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); + if (lpfc_ncmd->cpu != cpu) + lpfc_printf_vlog(vport, + KERN_INFO, LOG_NVME_IOERR, + "6701 CPU Check cmpl: " + "cpu %d expect %d\n", + cpu, lpfc_ncmd->cpu); } #endif /* NVME targets need completion held off until the abort exchange * completes unless the NVME Rport is getting unregistered. */ - if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) { freqpriv = nCmd->private; freqpriv->nvme_buf = NULL; lpfc_ncmd->nvmeCmd = NULL; - spin_unlock(&lpfc_ncmd->buf_lock); + call_done = true; + } + spin_unlock(&lpfc_ncmd->buf_lock); + + /* Check if IO qualified for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + nCmd->io_dir == NVMEFC_FCP_READ && + nCmd->payload_length) { + /* Used when calculating average latency */ + lat = ktime_get_ns() - lpfc_ncmd->rx_cmd_start; + lpfc_update_cmf_cmpl(phba, lat, nCmd->payload_length, NULL); + } + + if (call_done) nCmd->done(nCmd); - } else - spin_unlock(&lpfc_ncmd->buf_lock); /* Call release with XB=1 to queue the IO into the abort list. */ lpfc_release_nvme_buf(phba, lpfc_ncmd); @@ -1202,6 +1215,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, { struct lpfc_hba *phba = vport->phba; struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; + struct nvme_common_command *sqe; struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq); union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t req_len; @@ -1249,6 +1263,10 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 5 */ wqe->fcp_iread.rsrvd5 = 0; + /* For a CMF Managed port, iod must be zero'ed */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, + LPFC_WQE_IOD_NONE); cstat->input_requests++; } } else { @@ -1258,8 +1276,14 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, cstat->control_requests++; } - if (pnode->nlp_nvme_info & NLP_NVME_NSLER) + if (pnode->nlp_nvme_info & NLP_NVME_NSLER) { bf_set(wqe_erp, &wqe->generic.wqe_com, 1); + sqe = &((struct nvme_fc_cmd_iu *) + nCmd->cmdaddr)->sqe.common; + if (sqe->opcode == nvme_admin_async_event) + bf_set(wqe_ffrq, &wqe->generic.wqe_com, 1); + } + /* * Finish initializing those WQE fields that are independent * of the nvme_cmnd request_buffer @@ -1339,11 +1363,11 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, first_data_sgl = sgl; lpfc_ncmd->seg_cnt = nCmd->sg_cnt; if (lpfc_ncmd->seg_cnt > lpfc_nvme_template.max_sgl_segments) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6058 Too many sg segments from " "NVME Transport. Max %d, " "nvmeIO sg_cnt %d\n", - phba->cfg_nvme_seg_cnt + 1, + phba->cfg_nvme_seg_cnt, lpfc_ncmd->seg_cnt); lpfc_ncmd->seg_cnt = 0; return 1; @@ -1362,7 +1386,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, j = 2; for (i = 0; i < nseg; i++) { if (data_sg == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6059 dptr err %d, nseg %d\n", i, nseg); lpfc_ncmd->seg_cnt = 0; @@ -1463,7 +1487,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, * and sg_cnt must zero. */ if (nCmd->payload_length != 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6063 NVME DMA Prep Err: sg_cnt %d " "payload_length x%x\n", nCmd->sg_cnt, nCmd->payload_length); @@ -1509,9 +1533,9 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_qhandle *lpfc_queue_info; struct lpfc_nvme_fcpreq_priv *freqpriv; struct nvme_common_command *sqe; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint64_t start = 0; -#endif + unsigned long iflag = 0; + struct nvme_fc_cmd_iu *nvme_cmd_iu; /* Validate pointers. LLDD fault handling with transport does * have timing races. @@ -1526,7 +1550,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if (unlikely(!hw_queue_handle)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, - "6117 Fail IO, NULL hw_queue_handle\n"); + "6117 Busy IO, NULL hw_queue_handle\n"); atomic_inc(&lport->xmt_fcp_err); ret = -EBUSY; goto out_fail; @@ -1534,11 +1558,6 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, phba = vport->phba; - if (vport->load_flag & FC_UNLOADING) { - ret = -ENODEV; - goto out_fail; - } - if (unlikely(vport->load_flag & FC_UNLOADING)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6124 Fail IO, Driver unload\n"); @@ -1582,9 +1601,9 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if ((ndlp->nlp_type & NLP_NVME_TARGET) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_NVME_IOERR, - "6036 Fail IO, DID x%06x not ready for " + "6036 Busy IO %p, DID x%06x not ready for " "IO. State x%x, Type x%x Flg x%x\n", - pnvme_rport->port_id, + freqpriv, pnvme_rport->port_id, ndlp->nlp_state, ndlp->nlp_type, ndlp->upcall_flags); atomic_inc(&lport->xmt_fcp_bad_ndlp); @@ -1597,13 +1616,67 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, * if the driver runs out of a resource. These should only be * issued on the admin queue, qidx 0 */ + nvme_cmd_iu = (struct nvme_fc_cmd_iu *)pnvme_fcreq->cmdaddr; if (!lpfc_queue_info->qidx && !pnvme_fcreq->sg_cnt) { - sqe = &((struct nvme_fc_cmd_iu *) - pnvme_fcreq->cmdaddr)->sqe.common; + sqe = &nvme_cmd_iu->sqe.common; if (sqe->opcode == nvme_admin_keep_alive) expedite = 1; } + /* Driver is setting the nvme command category field. For qidx > 0, + * the cmd IU category is 1000 (base 2) or 0x8 which is CSS value of 0. + * Hardcode this until the nvme transport evolves to track the CSS per + * controller. + * For qidx == 0, the admin cmd IU category is 0001 (base 2) or 0x1. + * The category field is located in word1 bits <11:8> of byte 2. Word1 + * if defined as a 3-byte array and a 4th flags byte. + */ +#if !defined(NVME_CMD_FORMAT_ID) + if (lpfc_queue_info->qidx) + nvme_cmd_iu->rsvd4[2] = 0x8; + else + nvme_cmd_iu->rsvd4[2] = 1; +#endif + + /* Check if IO qualifies for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + pnvme_fcreq->io_dir == NVMEFC_FCP_READ && + pnvme_fcreq->payload_length) { + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) { + /* If this is an IO from the upper layer, and we have + * outstanding deferred IOs, don't even bother trying + * to send this. Just put it directly on the pendq. + */ + spin_lock_irqsave(&phba->nvme_pendq_lock, iflag); + if (!list_empty(&phba->nvme_pendq) && + (freqpriv->status != -EAGAIN)) { + lpfc_nvme_insert_pend_io(phba, pnvme_fcreq, + pnvme_lport, + pnvme_rport, + hw_queue_handle, 0); + spin_unlock_irqrestore(&phba->nvme_pendq_lock, + iflag); + ret = 0; + goto out_fail; + } + spin_unlock_irqrestore(&phba->nvme_pendq_lock, iflag); + } + ret = lpfc_update_cmf_cmd(phba, pnvme_fcreq->payload_length); + if (ret) { + spin_lock_irqsave(&phba->nvme_pendq_lock, iflag); + lpfc_nvme_insert_pend_io(phba, pnvme_fcreq, pnvme_lport, + pnvme_rport, hw_queue_handle, + 1); + spin_unlock_irqrestore(&phba->nvme_pendq_lock, iflag); + ret = 0; + goto out_fail; + } + freqpriv->status = 0; + + /* Get start time for IO latency */ + start = ktime_get_ns(); + } + /* The node is shared with FCP IO, make sure the IO pending count does * not exceed the programmed depth. */ @@ -1611,14 +1684,14 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if ((atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) && !expedite) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, - "6174 Fail IO, ndlp qdepth exceeded: " + "6174 Busy IO, ndlp qdepth exceeded: " "idx %d DID %x pend %d qdepth %d\n", lpfc_queue_info->index, ndlp->nlp_DID, atomic_read(&ndlp->cmd_pending), ndlp->cmd_qdepth); atomic_inc(&lport->xmt_fcp_qdepth); ret = -EBUSY; - goto out_fail; + goto out_fail1; } } @@ -1634,11 +1707,11 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if (lpfc_ncmd == NULL) { atomic_inc(&lport->xmt_fcp_noxri); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, - "6065 Fail IO, driver buffer pool is empty: " + "6065 Busy IO, waiting for available buffer: " "idx %d DID %x\n", lpfc_queue_info->index, ndlp->nlp_DID); ret = -EBUSY; - goto out_fail; + goto out_fail1; } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (start) { @@ -1648,6 +1721,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, lpfc_ncmd->ts_cmd_start = 0; } #endif + lpfc_ncmd->rx_cmd_start = start; /* * Store the data needed by the driver to issue, abort, and complete @@ -1705,19 +1779,17 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if (lpfc_ncmd->ts_cmd_start) lpfc_ncmd->ts_cmd_wqput = ktime_get_ns(); - if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) { + if (phba->hdwqstat_on & LPFC_CHECK_NVME_IO) { cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - lpfc_ncmd->cpu = cpu; - if (idx != cpu) - lpfc_printf_vlog(vport, - KERN_INFO, LOG_NVME_IOERR, - "6702 CPU Check cmd: " - "cpu %d wq %d\n", - lpfc_ncmd->cpu, - lpfc_queue_info->index); - phba->sli4_hba.hdwq[idx].cpucheck_xmt_io[cpu]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); + lpfc_ncmd->cpu = cpu; + if (idx != cpu) + lpfc_printf_vlog(vport, + KERN_INFO, LOG_NVME_IOERR, + "6702 CPU Check cmd: " + "cpu %d wq %d\n", + lpfc_ncmd->cpu, + lpfc_queue_info->index); } #endif return 0; @@ -1731,6 +1803,9 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, } else cstat->control_requests--; lpfc_release_nvme_buf(phba, lpfc_ncmd); + out_fail1: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, + pnvme_fcreq->payload_length, NULL); out_fail: return ret; } @@ -1746,6 +1821,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, * Return value: * None **/ +#endif void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_wcqe_complete *abts_cmpl) @@ -1760,7 +1836,122 @@ lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, bf_get(lpfc_wcqe_c_request_tag, abts_cmpl), bf_get(lpfc_wcqe_c_status, abts_cmpl), bf_get(lpfc_wcqe_c_hw_status, abts_cmpl)); +#ifdef BUILD_NVME_FC lpfc_sli_release_iocbq(phba, cmdiocb); +#endif +} + +#ifdef BUILD_NVME_FC +/** + * Driver calls this routine to complete a pending nvme IO to the nvme + * transport. The IO is pending for one of two reasons: (1) The congestion + * management handling could not send it (2) The nvme abort handler is + * completing a pending IO. The caller must not hold the + * phba->nvme_pendq_lock as this routine upcalls the transport. + **/ +static void +lpfc_nvme_complete_pend_io(struct lpfc_hba *phba, + struct nvmefc_fcp_req *pnvme_fcreq) +{ + struct lpfc_nvme_fcpreq_priv *freqpriv = pnvme_fcreq->private; + + /* Complete the IO for the transport. */ + pnvme_fcreq->transferred_length = 0; + pnvme_fcreq->rcv_rsplen = 0; + pnvme_fcreq->status = NVME_SC_INTERNAL; + + /* Complete the driver's piece. */ + freqpriv->nvme_buf = NULL; + freqpriv->status = 0; + pnvme_fcreq->done(pnvme_fcreq); +} + +/** + * Driver calls this routine to insert an nvme IO to the driver's + * nvme pending IO list. The IO is pending because the congestion + * management handling could not send it. The caller is expected + * to hold the phba->nvme_pendq_lock. + **/ +static void +lpfc_nvme_insert_pend_io(struct lpfc_hba *phba, + struct nvmefc_fcp_req *pnvme_fcreq, + struct nvme_fc_local_port *pnvme_lport, + struct nvme_fc_remote_port *pnvme_rport, + void *hw_queue_handle, u32 to_head) +{ + struct lpfc_nvme_fcpreq_priv *freqpriv = pnvme_fcreq->private; + + lockdep_assert_held(&phba->nvme_pendq_lock); + + freqpriv->pnvme_lport = pnvme_lport; + freqpriv->pnvme_rport = pnvme_rport; + freqpriv->hw_queue_handle = hw_queue_handle; + freqpriv->pnvme_fcreq = pnvme_fcreq; + freqpriv->status = -EBUSY; + + /* Put IO back on Head of the pending queue to + * preserve IO order and not introduce transport + * timing races. + */ + if (!to_head) + list_add_tail(&freqpriv->nvme_pend_list, &phba->nvme_pendq); + else + list_add(&freqpriv->nvme_pend_list, &phba->nvme_pendq); + phba->nvme_pendq_cnt++; +} + +void +lpfc_nvme_issue_pend_io(struct work_struct *work) +{ + struct lpfc_hba *phba = + container_of(work, struct lpfc_hba, nvme_defer_work); + struct lpfc_nvme_fcpreq_priv *freqpriv; + unsigned long iflag = 0; + int ret = 0; + + while (atomic_read(&phba->nvme_abts_cnt) != 0) { + spin_lock_irqsave(&phba->nvme_pendq_lock, iflag); + list_remove_head(&phba->nvme_abts_pendq, freqpriv, + struct lpfc_nvme_fcpreq_priv, + nvme_abts_pend_list); + spin_unlock_irqrestore(&phba->nvme_pendq_lock, iflag); + + lpfc_nvme_complete_pend_io(phba, freqpriv->pnvme_fcreq); + atomic_dec(&phba->nvme_abts_cnt); + } + + spin_lock_irqsave(&phba->nvme_pendq_lock, iflag); + while (!list_empty(&phba->nvme_pendq)) { + list_remove_head(&phba->nvme_pendq, freqpriv, + struct lpfc_nvme_fcpreq_priv, nvme_pend_list); + phba->nvme_pendq_cnt--; + + /* Set the status to distinguish an IO the transport issued + * versus a driver retry. + */ + freqpriv->status = -EAGAIN; + + spin_unlock_irqrestore(&phba->nvme_pendq_lock, iflag); + ret = lpfc_nvme_fcp_io_submit(freqpriv->pnvme_lport, + freqpriv->pnvme_rport, + freqpriv->hw_queue_handle, + freqpriv->pnvme_fcreq); + + /* If the driver returns a failure code, then the IO has to be + * be completed as there no retry scheduled. Otherwise, the + * IO was either send or rescheduled. + */ + if (ret) + lpfc_nvme_complete_pend_io(phba, freqpriv->pnvme_fcreq); + + spin_lock_irqsave(&phba->nvme_pendq_lock, iflag); + + /* If we hit our BW threshold, no sense in continuing */ + if (freqpriv->status == -EBUSY) + break; + freqpriv->status = 0; + } + spin_unlock_irqrestore(&phba->nvme_pendq_lock, iflag); } /** @@ -1793,7 +1984,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; struct lpfc_nvme_fcpreq_priv *freqpriv; - union lpfc_wqe128 *abts_wqe; unsigned long flags; int ret_val; @@ -1830,11 +2020,26 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* If the hba is getting reset, this flag is set. It is * cleared when the reset is complete and rings reestablished. */ + spin_lock_irqsave(&phba->nvme_pendq_lock, flags); + if ((freqpriv->status == -EAGAIN) || + (freqpriv->status == -EBUSY)) { + /* Move the pending IO to the abts list*/ + list_del_init(&freqpriv->nvme_pend_list); + phba->nvme_pendq_cnt--; + + list_add_tail(&freqpriv->nvme_abts_pend_list, + &phba->nvme_abts_pendq); + atomic_inc(&phba->nvme_abts_cnt); + spin_unlock_irqrestore(&phba->nvme_pendq_lock, flags); + queue_work(phba->nvme_io, &phba->nvme_defer_work); + return; + } + spin_unlock_irqrestore(&phba->nvme_pendq_lock, flags); spin_lock_irqsave(&phba->hbalock, flags); /* driver queued commands are in process of being flushed */ if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6139 Driver in reset cleanup - flushing " "NVME Req now. hba_flag x%x\n", phba->hba_flag); @@ -1844,13 +2049,13 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, lpfc_nbuf = freqpriv->nvme_buf; if (!lpfc_nbuf) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, - "6140 NVME IO req has no matching lpfc nvme " - "io buffer. Skipping abort req.\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6140 NVME IO req %p has no matching lpfc nvme " + "io buffer. Skipping abort req.\n", freqpriv); return; } else if (!lpfc_nbuf->nvmeCmd) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6141 lpfc NVME IO req has no nvme_fcreq " "io buffer. Skipping abort req.\n"); return; @@ -1868,7 +2073,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, * has not seen it yet. */ if (lpfc_nbuf->nvmeCmd != pnvme_fcreq) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6143 NVME req mismatch: " "lpfc_nbuf x%px nvmeCmd x%px, " "pnvme_fcreq x%px. Skipping Abort xri x%x\n", @@ -1879,7 +2084,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Don't abort IOs no longer on the pending queue. */ if (!(nvmereq_wqe->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6142 NVME IO req x%px not queued - skipping " "abort req xri x%x\n", pnvme_fcreq, nvmereq_wqe->sli4_xritag); @@ -1893,7 +2098,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Outstanding abort is in progress */ if (nvmereq_wqe->iocb_flag & LPFC_DRIVER_ABORTED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6144 Outstanding NVME I/O Abort Request " "still pending on nvme_fcreq x%px, " "lpfc_ncmd %px xri x%x\n", @@ -1904,7 +2109,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, abts_buf = __lpfc_sli_get_iocbq(phba); if (!abts_buf) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6136 No available abort wqes. Skipping " "Abts req for nvme_fcreq x%px xri x%x\n", pnvme_fcreq, nvmereq_wqe->sli4_xritag); @@ -1914,37 +2119,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Ready - mark outstanding as aborted by driver. */ nvmereq_wqe->iocb_flag |= LPFC_DRIVER_ABORTED; - /* Complete prepping the abort wqe and issue to the FW. */ - abts_wqe = &abts_buf->wqe; - - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(abts_wqe, 0, sizeof(*abts_wqe)); - bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); - - /* word 7 */ - bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - bf_set(wqe_class, &abts_wqe->abort_cmd.wqe_com, - nvmereq_wqe->iocb.ulpClass); - - /* word 8 - tell the FW to abort the IO associated with this - * outstanding exchange ID. - */ - abts_wqe->abort_cmd.wqe_com.abort_tag = nvmereq_wqe->sli4_xritag; - - /* word 9 - this is the iotag for the abts_wqe completion. */ - bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com, - abts_buf->iotag); - - /* word 10 */ - bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - /* word 11 */ - bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + lpfc_nvme_prep_abort_wqe(abts_buf, nvmereq_wqe->sli4_xritag, 0); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_buf->iocb_flag |= LPFC_IO_NVME; @@ -1954,8 +2129,12 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, ret_val = lpfc_sli4_issue_wqe(phba, lpfc_nbuf->hdwq, abts_buf); spin_unlock(&lpfc_nbuf->buf_lock); spin_unlock_irqrestore(&phba->hbalock, flags); + + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (ret_val) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6137 Failed abts issue_wqe with status x%x " "for nvme_fcreq x%px.\n", ret_val, pnvme_fcreq); @@ -2037,6 +2216,7 @@ lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, lpfc_ncmd->start_time = jiffies; lpfc_ncmd->flags = 0; + /* Rsp SGE will be filled in when we rcv an IO * from the NVME Layer to be sent. * The cmd is going to be embedded so we need a SKIP SGE. @@ -2054,7 +2234,6 @@ lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, atomic_inc(&ndlp->cmd_pending); lpfc_ncmd->flags |= LPFC_SBUF_BUMP_QDEPTH; } - } else { qp = &phba->sli4_hba.hdwq[idx]; qp->empty_io_bufs++; @@ -2086,7 +2265,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) lpfc_ncmd->flags &= ~LPFC_SBUF_BUMP_QDEPTH; qp = lpfc_ncmd->hdwq; - if (lpfc_ncmd->flags & LPFC_SBUF_XBUSY) { + if (unlikely(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6310 XB release deferred for " "ox_id x%x on reqtag x%x\n", @@ -2101,6 +2280,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) } else lpfc_release_io_buf(phba, (struct lpfc_io_buf *)lpfc_ncmd, qp); } +#endif /** * lpfc_nvme_create_localport - Create/Bind an nvme localport instance. @@ -2122,6 +2302,7 @@ int lpfc_nvme_create_localport(struct lpfc_vport *vport) { int ret = 0; +#ifdef BUILD_NVME_FC struct lpfc_hba *phba = vport->phba; struct nvme_fc_port_info nfcp_info; struct nvme_fc_local_port *localport; @@ -2141,20 +2322,14 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) */ lpfc_nvme_template.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1; - /* Advertise how many hw queues we support based on fcp_io_sched */ - if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) - lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue; - else - lpfc_nvme_template.max_hw_queues = - phba->sli4_hba.num_present_cpu; - - if (!IS_ENABLED(CONFIG_NVME_FC)) - return ret; + /* Advertise how many hw queues we support based on cfg_hdw_queue, + * which will not exceed cpu count. + */ + lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue; /* localport is allocated from the stack, but the registration * call allocates heap memory as well as the private area. */ - ret = nvme_fc_register_localport(&nfcp_info, &lpfc_nvme_template, &vport->phba->pcidev->dev, &localport); if (!ret) { @@ -2171,6 +2346,8 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) vport->localport = localport; lport->vport = vport; vport->nvmei_support = 1; + INIT_LIST_HEAD(&lport->qhandle_list); + spin_lock_init(&lport->qhandle_list_lock); atomic_set(&lport->xmt_fcp_noxri, 0); atomic_set(&lport->xmt_fcp_bad_ndlp, 0); @@ -2187,10 +2364,14 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) atomic_set(&lport->fc4NvmeLsRequests, 0); atomic_set(&lport->fc4NvmeLsCmpls, 0); } +#else + ret = -ENOMEM; +#endif return ret; } +#if defined(BUILD_NVME) #if (IS_ENABLED(CONFIG_NVME_FC)) /* lpfc_nvme_lport_unreg_wait - Wait for the host to complete an lport unreg. * @@ -2211,6 +2392,8 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, int ret, i, pending = 0; struct lpfc_sli_ring *pring; struct lpfc_hba *phba = vport->phba; + struct lpfc_sli4_hdw_queue *qp; + int abts_scsi, abts_nvme; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2221,17 +2404,23 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { pending = 0; + abts_scsi = 0; + abts_nvme = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].io_wq->pring; + qp = &phba->sli4_hba.hdwq[i]; + pring = qp->io_wq->pring; if (!pring) continue; - if (pring->txcmplq_cnt) - pending += pring->txcmplq_cnt; + pending += pring->txcmplq_cnt; + abts_scsi += qp->abts_scsi_io_bufs; + abts_nvme += qp->abts_nvme_io_bufs; } - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6176 Lport x%px Localport x%px wait " - "timed out. Pending %d. Renewing.\n", - lport, vport->localport, pending); + "timed out. Pending %d [%d:%d]. " + "Renewing.\n", + lport, vport->localport, pending, + abts_scsi, abts_nvme); continue; } break; @@ -2241,6 +2430,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, lport, vport->localport); } #endif +#endif /** * lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport. @@ -2255,7 +2445,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, void lpfc_nvme_destroy_localport(struct lpfc_vport *vport) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; int ret; @@ -2305,7 +2495,7 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) void lpfc_nvme_update_localport(struct lpfc_vport *vport) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; @@ -2341,7 +2531,7 @@ lpfc_nvme_update_localport(struct lpfc_vport *vport) int lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC int ret = 0; struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; @@ -2350,6 +2540,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct nvme_fc_remote_port *remote_port; struct nvme_fc_port_info rpinfo; struct lpfc_nodelist *prev_ndlp = NULL; + struct fc_rport *srport = ndlp->rport; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NVME_DISC, "6006 Register NVME PORT. DID x%06x nlptype x%x\n", @@ -2379,6 +2570,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rpinfo.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); rpinfo.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); + if (srport) + rpinfo.dev_loss_tmo = srport->dev_loss_tmo; + else + rpinfo.dev_loss_tmo = vport->cfg_devloss_tmo; spin_lock_irq(&vport->phba->hbalock); oldrport = lpfc_ndlp_get_nrport(ndlp); @@ -2404,39 +2599,6 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_unlock_irq(&vport->phba->hbalock); rport = remote_port->private; if (oldrport) { - /* New remoteport record does not guarantee valid - * host private memory area. - */ - if (oldrport == remote_port->private) { - /* Same remoteport - ndlp should match. - * Just reuse. - */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, - LOG_NVME_DISC, - "6014 Rebind lport to current " - "remoteport x%px wwpn 0x%llx, " - "Data: x%x x%x x%px x%px x%x " - " x%06x\n", - remote_port, - remote_port->port_name, - remote_port->port_id, - remote_port->port_role, - oldrport->ndlp, - ndlp, - ndlp->nlp_type, - ndlp->nlp_DID); - - /* It's a complete rebind only if the driver - * is registering with the same ndlp. Otherwise - * the driver likely executed a node swap - * prior to this registration and the ndlp to - * remoteport binding needs to be redone. - */ - if (prev_ndlp == ndlp) - return 0; - - } - /* Sever the ndlp<->rport association * before dropping the ndlp ref from * register. @@ -2471,14 +2633,14 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "6022 Bind lport x%px to remoteport x%px " "rport x%px WWNN 0x%llx, " "Rport WWPN 0x%llx DID " - "x%06x Role x%x, ndlp %p prev_ndlp x%px\n", + "x%06x Role x%x, ndlp x%px prev_ndlp x%px\n", lport, remote_port, rport, rpinfo.node_name, rpinfo.port_name, rpinfo.port_id, rpinfo.port_role, ndlp, prev_ndlp); } else { lpfc_printf_vlog(vport, KERN_ERR, - LOG_NVME_DISC | LOG_NODE, + LOG_TRACE_EVENT, "6031 RemotePort Registration failed " "err: %d, DID x%06x\n", ret, ndlp->nlp_DID); @@ -2490,8 +2652,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) #endif } -/** - * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport +/* lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport * * If the ndlp represents an NVME Target, that we are logged into, * ping the NVME FC Transport layer to initiate a device rescan @@ -2500,7 +2661,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) void lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC struct lpfc_nvme_rport *nrport; struct nvme_fc_remote_port *remoteport = NULL; @@ -2519,12 +2680,12 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!nrport || !remoteport) goto rescan_exit; - /* Only rescan if we are an NVME target in the MAPPED state */ - if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY && - ndlp->nlp_state == NLP_STE_MAPPED_NODE) { + /* Rescan an NVME target in MAPPED state with DISCOVERY role set */ + if ((remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) && + (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { nvme_fc_rescan_remoteport(remoteport); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6172 NVME rescanned DID x%06x " "port_state x%x\n", ndlp->nlp_DID, remoteport->port_state); @@ -2552,7 +2713,7 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) void lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC int ret; struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; @@ -2607,7 +2768,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ret = nvme_fc_unregister_remoteport(remoteport); if (ret != 0) { lpfc_nlp_put(ndlp); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6167 NVME unregister failed %d " "port_state x%x\n", ret, remoteport->port_state); @@ -2617,7 +2778,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) input_err: #endif - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6168 State error: lport x%px, rport x%px FCID x%06x\n", vport->localport, ndlp->rport, ndlp->nlp_DID); } @@ -2637,16 +2798,16 @@ lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, struct lpfc_io_buf *lpfc_ncmd) { +#ifdef BUILD_NVME_FC uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); struct nvmefc_fcp_req *nvme_cmd = NULL; struct lpfc_nodelist *ndlp = lpfc_ncmd->ndlp; - if (ndlp) lpfc_sli4_abts_err_handler(phba, ndlp, axri); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6311 nvme_cmd %p xri x%x tag x%x abort complete and " + "6311 nvme_cmd x%px xri x%x tag x%x abort complete and " "xri released\n", lpfc_ncmd->nvmeCmd, xri, lpfc_ncmd->cur_iocbq.iotag); @@ -2661,6 +2822,7 @@ lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, lpfc_ncmd->nvmeCmd = NULL; } lpfc_release_nvme_buf(phba, lpfc_ncmd); +#endif } /** @@ -2702,7 +2864,7 @@ lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) * dump a message. Something is wrong. */ if ((wait_cnt % 1000) == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6178 NVME IO not empty, " "cnt %d\n", wait_cnt); } @@ -2711,14 +2873,17 @@ lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) } void -lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn) +lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + uint32_t stat, uint32_t param) { -#if (IS_ENABLED(CONFIG_NVME_FC)) +#ifdef BUILD_NVME_FC struct lpfc_io_buf *lpfc_ncmd; struct nvmefc_fcp_req *nCmd; - struct lpfc_nvme_fcpreq_priv *freqpriv; + struct lpfc_wcqe_complete wcqe; + struct lpfc_wcqe_complete *wcqep = &wcqe; - if (!pwqeIn->context1) { + lpfc_ncmd = (struct lpfc_io_buf *)pwqeIn->context1; + if (!lpfc_ncmd) { lpfc_sli_release_iocbq(phba, pwqeIn); return; } @@ -2728,31 +2893,30 @@ lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn) lpfc_sli_release_iocbq(phba, pwqeIn); return; } - lpfc_ncmd = (struct lpfc_io_buf *)pwqeIn->context1; spin_lock(&lpfc_ncmd->buf_lock); - if (!lpfc_ncmd->nvmeCmd) { + nCmd = lpfc_ncmd->nvmeCmd; + if (!nCmd) { spin_unlock(&lpfc_ncmd->buf_lock); lpfc_release_nvme_buf(phba, lpfc_ncmd); return; } + spin_unlock(&lpfc_ncmd->buf_lock); - nCmd = lpfc_ncmd->nvmeCmd; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, "6194 NVME Cancel xri %x\n", lpfc_ncmd->cur_iocbq.sli4_xritag); - nCmd->transferred_length = 0; - nCmd->rcv_rsplen = 0; - nCmd->status = NVME_SC_INTERNAL; - freqpriv = nCmd->private; - freqpriv->nvme_buf = NULL; - lpfc_ncmd->nvmeCmd = NULL; - - spin_unlock(&lpfc_ncmd->buf_lock); - nCmd->done(nCmd); + wcqep->word0 = 0; + bf_set(lpfc_wcqe_c_status, wcqep, stat); + wcqep->parameter = param; + wcqep->word3 = 0; /* xb is 0 */ /* Call release with XB=1 to queue the IO into the abort list. */ - lpfc_release_nvme_buf(phba, lpfc_ncmd); + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + bf_set(lpfc_wcqe_c_xb, wcqep, 1); + + (pwqeIn->wqe_cmpl)(phba, pwqeIn, wcqep); #endif } + diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index 593c48ff6..589192951 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -21,7 +21,16 @@ * included with this package. * ********************************************************************/ -#define LPFC_NVME_DEFAULT_SEGS (64 + 1) /* 256K IOs */ +#if !defined(BUILD_NVME) +#define FC_TYPE_NVME 0x28 +#endif + +#define LPFC_NVME_MIN_SEGS 16 +#define LPFC_NVME_DEFAULT_SEGS 66 /* 256K IOs - 64 + 2 */ +#define LPFC_NVME_MAX_SEGS 510 +#define LPFC_NVMET_MIN_POSTBUF 16 +#define LPFC_NVMET_DEFAULT_POSTBUF 1024 +#define LPFC_NVMET_MAX_POSTBUF 4096 #define LPFC_NVME_ERSP_LEN 0x20 @@ -30,14 +39,12 @@ #define LPFC_NVME_FB_SHIFT 9 #define LPFC_NVME_MAX_FB (1 << 20) /* 1M */ -#define LPFC_MAX_NVME_INFO_TMP_LEN 100 -#define LPFC_NVME_INFO_MORE_STR "\nCould be more info...\n" - #define lpfc_ndlp_get_nrport(ndlp) \ ((!ndlp->nrport || (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG)) \ ? NULL : ndlp->nrport) struct lpfc_nvme_qhandle { + struct list_head list; /* list entry to maintain qhandle list */ uint32_t index; /* WQ index to use */ uint32_t qidx; /* queue index passed to create */ uint32_t cpu_id; /* current cpu id at time of create */ @@ -62,6 +69,9 @@ struct lpfc_nvme_lport { atomic_t cmpl_fcp_err; atomic_t cmpl_ls_xb; atomic_t cmpl_ls_err; + /* Maintaining qhandle list */ + struct list_head qhandle_list; + spinlock_t qhandle_list_lock; }; struct lpfc_nvme_rport { @@ -73,4 +83,13 @@ struct lpfc_nvme_rport { struct lpfc_nvme_fcpreq_priv { struct lpfc_io_buf *nvme_buf; + + /* Used for pending IO */ + struct list_head nvme_pend_list; + struct list_head nvme_abts_pend_list; + struct nvme_fc_local_port *pnvme_lport; + struct nvme_fc_remote_port *pnvme_rport; + void *hw_queue_handle; + struct nvmefc_fcp_req *pnvme_fcreq; + uint32_t status; }; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index ce2e2b58f..bb6fe445d 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channsel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -35,11 +35,14 @@ #include #include #include - +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) #include #include #include - +#define BUILD_NVMET_FC +#endif +#endif #include "lpfc_version.h" #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -56,6 +59,7 @@ #include "lpfc_vport.h" #include "lpfc_debugfs.h" +#ifdef BUILD_NVMET_FC static struct lpfc_iocbq *lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *, struct lpfc_nvmet_rcv_ctx *, dma_addr_t rspbuf, @@ -302,7 +306,11 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe) { struct lpfc_nvmet_tgtport *tgtp; +#if defined(BUILD_NVME_PLUS) + struct nvmefc_ls_rsp *rsp; +#else struct nvmefc_tgt_ls_req *rsp; +#endif struct lpfc_nvmet_rcv_ctx *ctxp; uint32_t status, result; @@ -311,7 +319,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ctxp = cmdwqe->context2; if (ctxp->state != LPFC_NVMET_STE_LS_RSP || ctxp->entry_cnt != 2) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6410 NVMET LS cmpl state mismatch IO x%x: " "%d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); @@ -351,6 +359,7 @@ out: rsp->done(rsp); kfree(ctxp); } +#endif /** * lpfc_nvmet_ctxbuf_post - Repost a NVMET RQ DMA buffer and clean up context @@ -368,7 +377,7 @@ out: void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) { -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +#ifdef BUILD_NVMET_FC struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; @@ -378,15 +387,8 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) int cpu; unsigned long iflag; - if (ctxp->txrdy) { - dma_pool_free(phba->txrdy_payload_pool, ctxp->txrdy, - ctxp->txrdy_phys); - ctxp->txrdy = NULL; - ctxp->txrdy_phys = 0; - } - if (ctxp->state == LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6411 NVMET free, already free IO x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); } @@ -430,7 +432,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; ctxp->wqeq = NULL; - ctxp->txrdy = NULL; ctxp->offset = 0; ctxp->phba = phba; ctxp->size = size; @@ -466,7 +467,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) if (!queue_work(phba->wq, &ctx_buf->defer_work)) { atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6181 Unable to queue deferred work " "for oxid x%x. " "FCP Drop IO [x%x x%x x%x]\n", @@ -500,6 +501,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) #endif } +#ifdef BUILD_NVMET_FC #ifdef CONFIG_SCSI_LPFC_DEBUG_FS static void lpfc_nvmet_ktime(struct lpfc_hba *phba, @@ -695,7 +697,7 @@ out: phba->ktime_status_samples++; } #endif - +#endif /** * lpfc_nvmet_xmt_fcp_op_cmp - Completion handler for FCP Response * @phba: Pointer to HBA context object. @@ -706,6 +708,7 @@ out: * lock held. This function is the completion handler for NVME FCP commands * The function frees memory resources used for the NVME commands. **/ +#ifdef BUILD_NVMET_FC static void lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe) @@ -715,7 +718,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_nvmet_rcv_ctx *ctxp; uint32_t status, result, op, start_clean, logerr; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint32_t id; + int id; #endif ctxp = cmdwqe->context2; @@ -822,23 +825,27 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, rsp->done(rsp); } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { id = raw_smp_processor_id(); - if (id < LPFC_CHECK_CPU_CNT) { - if (ctxp->cpu != id) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6704 CPU Check cmdcmpl: " - "cpu %d expect %d\n", - id, ctxp->cpu); - phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_cmpl_io[id]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); + if (ctxp->cpu != id) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6704 CPU Check cmdcmpl: " + "cpu %d expect %d\n", + id, ctxp->cpu); } #endif } +#if defined(BUILD_NVME_PLUS) +static int +lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + struct nvmefc_ls_rsp *rsp) +#else static int lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_ls_req *rsp) +#endif { struct lpfc_nvmet_rcv_ctx *ctxp = container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.ls_req); @@ -851,9 +858,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, struct ulp_bde64 bpl; int rc; - if (phba->pport->load_flag & FC_UNLOADING) - return -ENODEV; - if (phba->pport->load_flag & FC_UNLOADING) return -ENODEV; @@ -862,7 +866,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, if ((ctxp->state != LPFC_NVMET_STE_LS_RCV) || (ctxp->entry_cnt != 1)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6412 NVMET LS rsp state mismatch " "oxid x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); @@ -874,7 +878,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, rsp->rsplen); if (nvmewqeq == NULL) { atomic_inc(&nvmep->xmt_ls_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6150 LS Drop IO x%x: Prep\n", ctxp->oxid); lpfc_in_buf_free(phba, &nvmebuf->dbuf); @@ -914,7 +918,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, } /* Give back resources */ atomic_inc(&nvmep->xmt_ls_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6151 LS Drop IO x%x: Issue %d\n", ctxp->oxid, rc); @@ -939,11 +943,9 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, struct lpfc_sli_ring *pring; unsigned long iflags; int rc; - - if (phba->pport->load_flag & FC_UNLOADING) { - rc = -ENODEV; - goto aerr; - } +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + int id; +#endif if (phba->pport->load_flag & FC_UNLOADING) { rc = -ENODEV; @@ -962,16 +964,14 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, if (!ctxp->hdwq) ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid]; - if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { - int id = raw_smp_processor_id(); - if (id < LPFC_CHECK_CPU_CNT) { - if (rsp->hwqid != id) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6705 CPU Check OP: " - "cpu %d expect %d\n", - id, rsp->hwqid); - phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_xmt_io[id]++; - } + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { + id = raw_smp_processor_id(); + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); + if (rsp->hwqid != id) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6705 CPU Check OP: " + "cpu %d expect %d\n", + id, rsp->hwqid); ctxp->cpu = id; /* Setup cpu for cmpl check */ } #endif @@ -980,7 +980,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, if ((ctxp->flag & LPFC_NVMET_ABTS_RCV) || (ctxp->state == LPFC_NVMET_STE_ABORT)) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6102 IO oxid x%x aborted\n", ctxp->oxid); rc = -ENXIO; @@ -990,7 +990,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, nvmewqeq = lpfc_nvmet_prep_fcp_wqe(phba, ctxp); if (nvmewqeq == NULL) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6152 FCP Drop IO x%x: Prep\n", ctxp->oxid); rc = -ENXIO; @@ -1038,7 +1038,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, /* Give back resources */ atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6153 FCP Drop IO x%x: Issue: %d\n", ctxp->oxid, rc); @@ -1071,9 +1071,6 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, struct lpfc_queue *wq; unsigned long flags; - if (phba->pport->load_flag & FC_UNLOADING) - return; - if (phba->pport->load_flag & FC_UNLOADING) return; @@ -1141,7 +1138,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, ctxp->flag, ctxp->oxid); else if (ctxp->state != LPFC_NVMET_STE_DONE && ctxp->state != LPFC_NVMET_STE_ABORT) - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6413 NVMET release bad state %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); @@ -1188,7 +1185,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, return; } - tgtp = phba->targetport->private; + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; if (tgtp) atomic_inc(&tgtp->rcv_fcp_cmd_defer); @@ -1199,6 +1196,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } +#ifdef OOB_FC_TRANSPORT static void lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) { @@ -1210,10 +1208,11 @@ lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) phba = tgtp->phba; rc = lpfc_issue_els_rscn(phba->pport, 0); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6420 NVMET subsystem change: Notification %s\n", (rc) ? "Failed" : "Sent"); } +#endif static struct nvmet_fc_target_template lpfc_tgttemplate = { .targetport_delete = lpfc_nvmet_targetport_delete, @@ -1222,7 +1221,9 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { .fcp_abort = lpfc_nvmet_xmt_fcp_abort, .fcp_req_release = lpfc_nvmet_xmt_fcp_release, .defer_rcv = lpfc_nvmet_defer_rcv, +#ifdef OOB_FC_TRANSPORT .discovery_event = lpfc_nvmet_discovery_event, +#endif .max_hw_queues = 1, .max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS, @@ -1304,7 +1305,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) phba->sli4_hba.num_possible_cpu * phba->cfg_nvmet_mrq, sizeof(struct lpfc_nvmet_ctx_info), GFP_KERNEL); if (!phba->sli4_hba.nvmet_ctx_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6419 Failed allocate memory for " "nvmet context lists\n"); return -ENOMEM; @@ -1362,7 +1363,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) for (i = 0; i < phba->sli4_hba.nvmet_xri_cnt; i++) { ctx_buf = kzalloc(sizeof(*ctx_buf), GFP_KERNEL); if (!ctx_buf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6404 Ran out of memory for NVMET\n"); return -ENOMEM; } @@ -1371,7 +1372,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) GFP_KERNEL); if (!ctx_buf->context) { kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6405 Ran out of NVMET " "context memory\n"); return -ENOMEM; @@ -1383,7 +1384,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) if (!ctx_buf->iocbq) { kfree(ctx_buf->context); kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6406 Ran out of NVMET iocb/WQEs\n"); return -ENOMEM; } @@ -1402,7 +1403,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) lpfc_sli_release_iocbq(phba, ctx_buf->iocbq); kfree(ctx_buf->context); kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6407 Ran out of NVMET XRIs\n"); return -ENOMEM; } @@ -1444,14 +1445,16 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) } return 0; } +#endif int lpfc_nvmet_create_targetport(struct lpfc_hba *phba) { + int error = 0; +#ifdef BUILD_NVMET_FC struct lpfc_vport *vport = phba->pport; struct lpfc_nvmet_tgtport *tgtp; struct nvmet_fc_port_info pinfo; - int error; if (phba->targetport) return 0; @@ -1473,15 +1476,11 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) lpfc_tgttemplate.max_hw_queues = phba->cfg_hdw_queue; lpfc_tgttemplate.target_features = NVMET_FCTGTFEAT_READDATA_RSP; -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) error = nvmet_fc_register_targetport(&pinfo, &lpfc_tgttemplate, &phba->pcidev->dev, &phba->targetport); -#else - error = -ENOENT; -#endif if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6025 Cannot register NVME targetport x%x: " "portnm %llx nodenm %llx segs %d qs %d\n", error, @@ -1543,12 +1542,16 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) atomic_set(&tgtp->defer_fod, 0); atomic_set(&tgtp->defer_wqfull, 0); } +#else + error = -ENOMEM; +#endif return error; } int lpfc_nvmet_update_targetport(struct lpfc_hba *phba) { +#ifdef BUILD_NVMET_FC struct lpfc_vport *vport = phba->pport; if (!phba->targetport) @@ -1559,355 +1562,14 @@ lpfc_nvmet_update_targetport(struct lpfc_hba *phba) phba->targetport, vport->fc_myDID); phba->targetport->port_id = vport->fc_myDID; - return 0; -} - -/** - * lpfc_sli4_nvmet_xri_aborted - Fast-path process of nvmet xri abort - * @phba: pointer to lpfc hba data structure. - * @axri: pointer to the nvmet xri abort wcqe structure. - * - * This routine is invoked by the worker thread to process a SLI4 fast-path - * NVMET aborted xri. - **/ -void -lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri) -{ -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); - struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; - struct lpfc_nvmet_tgtport *tgtp; - struct nvmefc_tgt_fcp_req *req = NULL; - struct lpfc_nodelist *ndlp; - unsigned long iflag = 0; - int rrq_empty = 0; - bool released = false; - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6317 XB aborted xri x%x rxid x%x\n", xri, rxid); - - if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) - return; - - if (phba->targetport) { - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - atomic_inc(&tgtp->xmt_fcp_xri_abort_cqe); - } - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_for_each_entry_safe(ctxp, next_ctxp, - &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, - list) { - if (ctxp->ctxbuf->sglq->sli4_xritag != xri) - continue; - - spin_lock(&ctxp->ctxlock); - /* Check if we already received a free context call - * and we have completed processing an abort situation. - */ - if (ctxp->flag & LPFC_NVMET_CTX_RLS && - !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { - list_del_init(&ctxp->list); - released = true; - } - ctxp->flag &= ~LPFC_NVMET_XBUSY; - spin_unlock(&ctxp->ctxlock); - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - - rrq_empty = list_empty(&phba->active_rrq_list); - spin_unlock_irqrestore(&phba->hbalock, iflag); - ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || - ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { - lpfc_set_rrq_active(phba, ndlp, - ctxp->ctxbuf->sglq->sli4_lxritag, - rxid, 1); - lpfc_sli4_abts_err_handler(phba, ndlp, axri); - } - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6318 XB aborted oxid x%x flg x%x (%x)\n", - ctxp->oxid, ctxp->flag, released); - if (released) - lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); - - if (rrq_empty) - lpfc_worker_wake_up(phba); - return; - } - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri); - if (ctxp) { - /* - * Abort already done by FW, so BA_ACC sent. - * However, the transport may be unaware. - */ - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6323 NVMET Rcv ABTS xri x%x ctxp state x%x " - "flag x%x oxid x%x rxid x%x\n", - xri, ctxp->state, ctxp->flag, ctxp->oxid, - rxid); - - spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= LPFC_NVMET_ABTS_RCV; - ctxp->state = LPFC_NVMET_STE_ABORT; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - - lpfc_nvmeio_data(phba, - "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, raw_smp_processor_id(), 0); - - req = &ctxp->ctx.fcp_req; - if (req) - nvmet_fc_rcv_fcp_abort(phba->targetport, req); - } -#endif -} - -int -lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, - struct fc_frame_header *fc_hdr) -{ -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_hba *phba = vport->phba; - struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; - struct nvmefc_tgt_fcp_req *rsp; - uint32_t sid; - uint16_t oxid, xri; - unsigned long iflag = 0; - - sid = sli4_sid_from_fc_hdr(fc_hdr); - oxid = be16_to_cpu(fc_hdr->fh_ox_id); - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_for_each_entry_safe(ctxp, next_ctxp, - &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, - list) { - if (ctxp->oxid != oxid || ctxp->sid != sid) - continue; - - xri = ctxp->ctxbuf->sglq->sli4_xritag; - - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= LPFC_NVMET_ABTS_RCV; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - - lpfc_nvmeio_data(phba, - "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, raw_smp_processor_id(), 0); - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6319 NVMET Rcv ABTS:acc xri x%x\n", xri); - - rsp = &ctxp->ctx.fcp_req; - nvmet_fc_rcv_fcp_abort(phba->targetport, rsp); - - /* Respond with BA_ACC accordingly */ - lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); - return 0; - } - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - /* check the wait list */ - if (phba->sli4_hba.nvmet_io_wait_cnt) { - struct rqb_dmabuf *nvmebuf; - struct fc_frame_header *fc_hdr_tmp; - u32 sid_tmp; - u16 oxid_tmp; - bool found = false; - - spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); - - /* match by oxid and s_id */ - list_for_each_entry(nvmebuf, - &phba->sli4_hba.lpfc_nvmet_io_wait_list, - hbuf.list) { - fc_hdr_tmp = (struct fc_frame_header *) - (nvmebuf->hbuf.virt); - oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id); - sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp); - if (oxid_tmp != oxid || sid_tmp != sid) - continue; - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6321 NVMET Rcv ABTS oxid x%x from x%x " - "is waiting for a ctxp\n", - oxid, sid); - - list_del_init(&nvmebuf->hbuf.list); - phba->sli4_hba.nvmet_io_wait_cnt--; - found = true; - break; - } - spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock, - iflag); - - /* free buffer since already posted a new DMA buffer to RQ */ - if (found) { - nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); - /* Respond with BA_ACC accordingly */ - lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); - return 0; - } - } - - /* check active list */ - ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid); - if (ctxp) { - xri = ctxp->ctxbuf->sglq->sli4_xritag; - - spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - - lpfc_nvmeio_data(phba, - "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, raw_smp_processor_id(), 0); - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x " - "flag x%x state x%x\n", - ctxp->oxid, xri, ctxp->flag, ctxp->state); - - if (ctxp->flag & LPFC_NVMET_TNOTIFY) { - /* Notify the transport */ - nvmet_fc_rcv_fcp_abort(phba->targetport, - &ctxp->ctx.fcp_req); - } else { - cancel_work_sync(&ctxp->ctxbuf->defer_work); - spin_lock_irqsave(&ctxp->ctxlock, iflag); - lpfc_nvmet_defer_release(phba, ctxp); - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - } - lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, - ctxp->oxid); - - lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); - return 0; - } - - lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n", - oxid, raw_smp_processor_id(), 1); - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid); - - /* Respond with BA_RJT accordingly */ - lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); #endif return 0; } -static void -lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, - struct lpfc_nvmet_rcv_ctx *ctxp) -{ - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *nvmewqeq; - struct lpfc_iocbq *next_nvmewqeq; - unsigned long iflags; - struct lpfc_wcqe_complete wcqe; - struct lpfc_wcqe_complete *wcqep; - - pring = wq->pring; - wcqep = &wcqe; - - /* Fake an ABORT error code back to cmpl routine */ - memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete)); - bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT); - wcqep->parameter = IOERR_ABORT_REQUESTED; - - spin_lock_irqsave(&pring->ring_lock, iflags); - list_for_each_entry_safe(nvmewqeq, next_nvmewqeq, - &wq->wqfull_list, list) { - if (ctxp) { - /* Checking for a specific IO to flush */ - if (nvmewqeq->context2 == ctxp) { - list_del(&nvmewqeq->list); - spin_unlock_irqrestore(&pring->ring_lock, - iflags); - lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, - wcqep); - return; - } - continue; - } else { - /* Flush all IOs */ - list_del(&nvmewqeq->list); - spin_unlock_irqrestore(&pring->ring_lock, iflags); - lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep); - spin_lock_irqsave(&pring->ring_lock, iflags); - } - } - if (!ctxp) - wq->q_flag &= ~HBA_NVMET_WQFULL; - spin_unlock_irqrestore(&pring->ring_lock, iflags); -} - -void -lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, - struct lpfc_queue *wq) -{ -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *nvmewqeq; - struct lpfc_nvmet_rcv_ctx *ctxp; - unsigned long iflags; - int rc; - - /* - * Some WQE slots are available, so try to re-issue anything - * on the WQ wqfull_list. - */ - pring = wq->pring; - spin_lock_irqsave(&pring->ring_lock, iflags); - while (!list_empty(&wq->wqfull_list)) { - list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq, - list); - spin_unlock_irqrestore(&pring->ring_lock, iflags); - ctxp = (struct lpfc_nvmet_rcv_ctx *)nvmewqeq->context2; - rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); - spin_lock_irqsave(&pring->ring_lock, iflags); - if (rc == -EBUSY) { - /* WQ was full again, so put it back on the list */ - list_add(&nvmewqeq->list, &wq->wqfull_list); - spin_unlock_irqrestore(&pring->ring_lock, iflags); - return; - } - if (rc == WQE_SUCCESS) { -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (ctxp->ts_cmd_nvme) { - if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) - ctxp->ts_status_wqput = ktime_get_ns(); - else - ctxp->ts_data_wqput = ktime_get_ns(); - } -#endif - } else { - WARN_ON(rc); - } - } - wq->q_flag &= ~HBA_NVMET_WQFULL; - spin_unlock_irqrestore(&pring->ring_lock, iflags); - -#endif -} - void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) { -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +#ifdef BUILD_NVMET_FC struct lpfc_nvmet_tgtport *tgtp; struct lpfc_queue *wq; uint32_t qidx; @@ -1925,7 +1587,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) nvmet_fc_unregister_targetport(phba->targetport); if (!wait_for_completion_timeout(&tport_unreg_cmp, msecs_to_jiffies(LPFC_NVMET_WAIT_TMO))) - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6179 Unreg targetport x%px timeout " "reached.\n", phba->targetport); lpfc_nvmet_cleanup_io_context(phba); @@ -1951,19 +1613,16 @@ static void lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct hbq_dmabuf *nvmebuf) { -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +#ifdef BUILD_NVMET_FC struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; struct lpfc_nvmet_rcv_ctx *ctxp; uint32_t *payload; uint32_t size, oxid, sid, rc; - fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); - oxid = be16_to_cpu(fc_hdr->fh_ox_id); - - if (!phba->targetport) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6154 LS Drop IO x%x\n", oxid); + if (!nvmebuf || !phba->targetport) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6154 LS Drop IO\n"); oxid = 0; size = 0; sid = 0; @@ -1971,6 +1630,9 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; } + fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; payload = (uint32_t *)(nvmebuf->dbuf.virt); size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); @@ -1979,14 +1641,15 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ctxp = kzalloc(sizeof(struct lpfc_nvmet_rcv_ctx), GFP_ATOMIC); if (ctxp == NULL) { atomic_inc(&tgtp->rcv_ls_req_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6155 LS Drop IO x%x: Alloc\n", oxid); dropit: lpfc_nvmeio_data(phba, "NVMET LS DROP: " "xri x%x sz %d from %06x\n", oxid, size, sid); - lpfc_in_buf_free(phba, &nvmebuf->dbuf); + if (nvmebuf) + lpfc_in_buf_free(phba, &nvmebuf->dbuf); return; } ctxp->phba = phba; @@ -2007,8 +1670,13 @@ dropit: * lpfc_nvmet_xmt_ls_rsp_cmp should free the allocated ctxp. */ atomic_inc(&tgtp->rcv_ls_req_in); +#if defined(BUILD_NVME_PLUS) + rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &ctxp->ctx.ls_req, + payload, size); +#else rc = nvmet_fc_rcv_ls_req(phba->targetport, &ctxp->ctx.ls_req, payload, size); +#endif lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, "6037 NVMET Unsol rcv: sz %d rc %d: %08x %08x %08x " @@ -2025,139 +1693,24 @@ dropit: oxid, size, sid); atomic_inc(&tgtp->rcv_ls_req_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6156 LS Drop IO x%x: nvmet_fc_rcv_ls_req %d\n", ctxp->oxid, rc); /* We assume a rcv'ed cmd ALWAYs fits into 1 buffer */ - lpfc_in_buf_free(phba, &nvmebuf->dbuf); + if (nvmebuf) + lpfc_in_buf_free(phba, &nvmebuf->dbuf); atomic_inc(&tgtp->xmt_ls_abort); lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, sid, oxid); #endif } -static void -lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) -{ -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; - struct lpfc_hba *phba = ctxp->phba; - struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; - struct lpfc_nvmet_tgtport *tgtp; - uint32_t *payload, qno; - uint32_t rc; - unsigned long iflags; - - if (!nvmebuf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6159 process_rcv_fcp_req, nvmebuf is NULL, " - "oxid: x%x flg: x%x state: x%x\n", - ctxp->oxid, ctxp->flag, ctxp->state); - spin_lock_irqsave(&ctxp->ctxlock, iflags); - lpfc_nvmet_defer_release(phba, ctxp); - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, - ctxp->oxid); - return; - } - - if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6324 IO oxid x%x aborted\n", - ctxp->oxid); - return; - } - - payload = (uint32_t *)(nvmebuf->dbuf.virt); - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - ctxp->flag |= LPFC_NVMET_TNOTIFY; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (ctxp->ts_isr_cmd) - ctxp->ts_cmd_nvme = ktime_get_ns(); -#endif - /* - * The calling sequence should be: - * nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done - * lpfc_nvmet_xmt_fcp_op_cmp should free the allocated ctxp. - * When we return from nvmet_fc_rcv_fcp_req, all relevant info - * the NVME command / FC header is stored. - * A buffer has already been reposted for this IO, so just free - * the nvmebuf. - */ - rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->ctx.fcp_req, - payload, ctxp->size); - /* Process FCP command */ - if (rc == 0) { - atomic_inc(&tgtp->rcv_fcp_cmd_out); - spin_lock_irqsave(&ctxp->ctxlock, iflags); - if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) || - (nvmebuf != ctxp->rqb_buffer)) { - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - return; - } - ctxp->rqb_buffer = NULL; - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ - return; - } - - /* Processing of FCP command is deferred */ - if (rc == -EOVERFLOW) { - lpfc_nvmeio_data(phba, "NVMET RCV BUSY: xri x%x sz %d " - "from %06x\n", - ctxp->oxid, ctxp->size, ctxp->sid); - atomic_inc(&tgtp->rcv_fcp_cmd_out); - atomic_inc(&tgtp->defer_fod); - spin_lock_irqsave(&ctxp->ctxlock, iflags); - if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - return; - } - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - /* - * Post a replacement DMA buffer to RQ and defer - * freeing rcv buffer till .defer_rcv callback - */ - qno = nvmebuf->idx; - lpfc_post_rq_buffer( - phba, phba->sli4_hba.nvmet_mrq_hdr[qno], - phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); - return; - } - ctxp->flag &= ~LPFC_NVMET_TNOTIFY; - atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", - ctxp->oxid, rc, - atomic_read(&tgtp->rcv_fcp_cmd_in), - atomic_read(&tgtp->rcv_fcp_cmd_out), - atomic_read(&tgtp->xmt_fcp_release)); - lpfc_nvmeio_data(phba, "NVMET FCP DROP: xri x%x sz %d from %06x\n", - ctxp->oxid, ctxp->size, ctxp->sid); - spin_lock_irqsave(&ctxp->ctxlock, iflags); - lpfc_nvmet_defer_release(phba, ctxp); - spin_unlock_irqrestore(&ctxp->ctxlock, iflags); - lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); -#endif -} - -static void -lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *work) -{ -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_nvmet_ctxbuf *ctx_buf = - container_of(work, struct lpfc_nvmet_ctxbuf, defer_work); - - lpfc_nvmet_process_rcv_fcp_req(ctx_buf); -#endif -} - +#ifdef BUILD_NVMET_FC static struct lpfc_nvmet_ctxbuf * lpfc_nvmet_replenish_context(struct lpfc_hba *phba, struct lpfc_nvmet_ctx_info *current_infop) { -#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_nvmet_ctxbuf *ctx_buf = NULL; struct lpfc_nvmet_ctx_info *get_infop; int i; @@ -2186,8 +1739,9 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba, /* Just take the entire context list, if there are any */ if (get_infop->nvmet_ctx_list_cnt) { - list_splice_init(&get_infop->nvmet_ctx_list, + list_splice(&get_infop->nvmet_ctx_list, ¤t_infop->nvmet_ctx_list); + INIT_LIST_HEAD(&get_infop->nvmet_ctx_list); current_infop->nvmet_ctx_list_cnt = get_infop->nvmet_ctx_list_cnt - 1; get_infop->nvmet_ctx_list_cnt = 0; @@ -2205,10 +1759,10 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba, get_infop = get_infop->nvmet_ctx_next_cpu; } -#endif /* Nothing found, all contexts for the MRQ are in-flight */ return NULL; } +#endif /** * lpfc_nvmet_unsol_fcp_buffer - Process an unsolicited event data buffer @@ -2232,6 +1786,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, uint64_t isr_timestamp, uint8_t cqflag) { +#ifdef BUILD_NVMET_FC struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; @@ -2241,12 +1796,9 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, unsigned long iflag; int current_cpu; - if (!IS_ENABLED(CONFIG_NVME_TARGET_FC)) - return; - ctx_buf = NULL; if (!nvmebuf || !phba->targetport) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6157 NVMET FCP Drop IO\n"); if (nvmebuf) lpfc_rq_buf_free(phba, &nvmebuf->hbuf); @@ -2277,15 +1829,13 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, size = nvmebuf->bytes_recv; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV) { - if (current_cpu < LPFC_CHECK_CPU_CNT) { - if (idx != current_cpu) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6703 CPU Check rcv: " - "cpu %d expect %d\n", - current_cpu, idx); - phba->sli4_hba.hdwq[idx].cpucheck_rcv_io[current_cpu]++; - } + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { + this_cpu_inc(phba->sli4_hba.c_stat->rcv_io); + if (idx != current_cpu) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6703 CPU Check rcv: " + "cpu %d expect %d\n", + current_cpu, idx); } #endif @@ -2311,6 +1861,10 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); atomic_inc(&tgtp->defer_ctx); + lpfc_throttle_log(phba, &phba->log, LOG_NVME_IOERR, + "6180 IO waiting, driver buffer pool is " + "empty: oxid x%x queue %d S_ID x%x\n", + oxid, qno, sli4_sid_from_fc_hdr(fc_hdr)); return; } @@ -2321,12 +1875,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); if (ctxp->state != LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6414 NVMET Context corrupt %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); } ctxp->wqeq = NULL; - ctxp->txrdy = NULL; ctxp->offset = 0; ctxp->phba = phba; ctxp->size = size; @@ -2364,7 +1917,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, if (!queue_work(phba->wq, &ctx_buf->defer_work)) { atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6325 Unable to queue work for oxid x%x. " "FCP Drop IO [x%x x%x x%x]\n", ctxp->oxid, @@ -2377,6 +1930,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid); } +#endif } /** @@ -2401,6 +1955,11 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, d_buf = piocb->context2; nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); + if (!nvmebuf) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3015 LS Drop IO\n"); + return; + } if (phba->nvmet_support == 0) { lpfc_in_buf_free(phba, &nvmebuf->dbuf); return; @@ -2429,10 +1988,17 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint64_t isr_timestamp, uint8_t cqflag) { +#ifdef BUILD_NVMET_FC + if (!nvmebuf) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3167 NVMET FCP Drop IO\n"); + return; + } if (phba->nvmet_support == 0) { lpfc_rq_buf_free(phba, &nvmebuf->hbuf); return; } +#endif lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag); } @@ -2461,6 +2027,7 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, * Pointer to the newly allocated/prepared nvme wqe data structure * NULL - when nvme wqe data structure allocation/preparation failed **/ +#ifdef BUILD_NVMET_FC static struct lpfc_iocbq * lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp, @@ -2471,7 +2038,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, union lpfc_wqe128 *wqe; if (!lpfc_is_link_up(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6104 NVMET prep LS wqe: link err: " "NPORT x%x oxid:x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2481,7 +2048,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, /* Allocate buffer for command wqe */ nvmewqe = lpfc_sli_get_iocbq(phba); if (nvmewqe == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6105 NVMET prep LS wqe: No WQE: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2492,7 +2059,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6106 NVMET prep LS wqe: No ndlp: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2595,14 +2162,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct scatterlist *sgel; union lpfc_wqe128 *wqe; struct ulp_bde64 *bde; - uint32_t *txrdy; dma_addr_t physaddr; - int i, cnt; + int i, cnt, nsegs; int do_pbde; int xc = 1; if (!lpfc_is_link_up(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6107 NVMET prep FCP wqe: link err:" "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2613,7 +2179,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6108 NVMET prep FCP wqe: no ndlp: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2621,13 +2187,14 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } if (rsp->sg_cnt > lpfc_tgttemplate.max_sgl_segments) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6109 NVMET prep FCP wqe: seg cnt err: " "NPORT x%x oxid x%x ste %d cnt %d\n", ctxp->sid, ctxp->oxid, ctxp->state, phba->cfg_nvme_seg_cnt); return NULL; } + nsegs = rsp->sg_cnt; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; nvmewqe = ctxp->wqeq; @@ -2635,7 +2202,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* Allocate buffer for command wqe */ nvmewqe = ctxp->ctxbuf->iocbq; if (nvmewqe == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6110 NVMET prep FCP wqe: No " "WQE: NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2653,7 +2220,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, (ctxp->state == LPFC_NVMET_STE_DATA)) { wqe = &nvmewqe->wqe; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6111 Wrong state NVMET FCP: %d cnt %d\n", ctxp->state, ctxp->entry_cnt); return NULL; @@ -2757,23 +2324,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, &lpfc_treceive_cmd_template.words[3], sizeof(uint32_t) * 9); - /* Words 0 - 2 : The first sg segment */ - txrdy = dma_pool_alloc(phba->txrdy_payload_pool, - GFP_KERNEL, &physaddr); - if (!txrdy) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6041 Bad txrdy buffer: oxid x%x\n", - ctxp->oxid); - return NULL; - } - ctxp->txrdy = txrdy; - ctxp->txrdy_phys = physaddr; - wqe->fcp_treceive.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; - wqe->fcp_treceive.bde.tus.f.bdeSize = TXRDY_PAYLOAD_LEN; - wqe->fcp_treceive.bde.addrLow = - cpu_to_le32(putPaddrLow(physaddr)); - wqe->fcp_treceive.bde.addrHigh = - cpu_to_le32(putPaddrHigh(physaddr)); + /* Words 0 - 2 : First SGE is skipped, set invalid BDE type */ + wqe->fcp_treceive.bde.tus.f.bdeFlags = LPFC_SGE_TYPE_SKIP; + wqe->fcp_treceive.bde.tus.f.bdeSize = 0; + wqe->fcp_treceive.bde.addrLow = 0; + wqe->fcp_treceive.bde.addrHigh = 0; /* Word 4 */ wqe->fcp_treceive.relative_offset = ctxp->offset; @@ -2808,17 +2363,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; - /* Setup 1 TXRDY and 1 SKIP SGE */ - txrdy[0] = 0; - txrdy[1] = cpu_to_be32(rsp->transfer_length); - txrdy[2] = 0; - - sgl->addr_hi = putPaddrHigh(physaddr); - sgl->addr_lo = putPaddrLow(physaddr); + /* Setup 2 SKIP SGEs */ + sgl->addr_hi = 0; + sgl->addr_lo = 0; sgl->word2 = 0; - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_SKIP); sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(TXRDY_PAYLOAD_LEN); + sgl->sge_len = 0; sgl++; sgl->addr_hi = 0; sgl->addr_lo = 0; @@ -2883,7 +2434,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, wqe->fcp_trsp.rsvd_12_15[0] = 0; /* Use rspbuf, NOT sg list */ - rsp->sg_cnt = 0; + nsegs = 0; sgl->word2 = 0; atomic_inc(&tgtp->xmt_fcp_rsp); break; @@ -2900,7 +2451,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT; nvmewqe->context1 = ndlp; - for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) { + for_each_sg(rsp->sg, sgel, nsegs, i) { physaddr = sg_dma_address(sgel); cnt = sg_dma_len(sgel); sgl->addr_hi = putPaddrHigh(physaddr); @@ -2915,7 +2466,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (i == 0) { bde = (struct ulp_bde64 *)&wqe->words[13]; if (do_pbde) { - /* Words 13-15 (PBDE) */ + /* Words 13-15 (PBDE)*/ bde->addrLow = sgl->addr_lo; bde->addrHigh = sgl->addr_hi; bde->tus.f.bdeSize = @@ -3027,7 +2578,6 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, result = wcqe->parameter; if (!ctxp) { - /* if context is clear, related io alrady complete */ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6070 ABTS cmpl: WCQE: %08x %08x %08x %08x\n", wcqe->word0, wcqe->total_data_placed, @@ -3042,7 +2592,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, /* Sanity check */ if (ctxp->state != LPFC_NVMET_STE_ABORT) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6112 ABTS Wrong state:%d oxid x%x\n", ctxp->state, ctxp->oxid); } @@ -3114,7 +2664,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, result, wcqe->word3); if (!ctxp) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6415 NVMET LS Abort No ctx: WCQE: " "%08x %08x %08x %08x\n", wcqe->word0, wcqe->total_data_placed, @@ -3125,7 +2675,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, } if (ctxp->state != LPFC_NVMET_STE_LS_ABORT) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6416 NVMET LS abort cmpl state mismatch: " "oxid x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); @@ -3158,7 +2708,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6134 Drop ABTS - wrong NDLP state x%x.\n", (ndlp) ? ndlp->nlp_state : NLP_STE_MAX_STATE); @@ -3204,6 +2754,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, bf_set(wqe_rcvoxid, &wqe_abts->xmit_sequence.wqe_com, xri); /* Word 10 */ + bf_set(wqe_dbde, &wqe_abts->xmit_sequence.wqe_com, 0); bf_set(wqe_iod, &wqe_abts->xmit_sequence.wqe_com, LPFC_WQE_IOD_WRITE); bf_set(wqe_lenloc, &wqe_abts->xmit_sequence.wqe_com, LPFC_WQE_LENLOC_WORD12); @@ -3238,9 +2789,9 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe128 *abts_wqe; struct lpfc_nodelist *ndlp; unsigned long flags; + u8 opt; int rc; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -3254,7 +2805,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6160 Drop ABORT - wrong NDLP state x%x.\n", (ndlp) ? ndlp->nlp_state : NLP_STE_MAX_STATE); @@ -3270,7 +2821,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, spin_lock_irqsave(&ctxp->ctxlock, flags); if (!ctxp->abort_wqeq) { atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6161 ABORT failed: No wqeqs: " "xri: x%x\n", ctxp->oxid); /* No failure to an ABTS request. */ @@ -3279,8 +2830,8 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, return 0; } abts_wqeq = ctxp->abort_wqeq; - abts_wqe = &abts_wqeq->wqe; ctxp->state = LPFC_NVMET_STE_ABORT; + opt = (ctxp->flag & LPFC_NVMET_ABTS_RCV) ? INHIBIT_ABORT : 0; spin_unlock_irqrestore(&ctxp->ctxlock, flags); /* Announce entry to new IO submit field. */ @@ -3297,7 +2848,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6163 Driver in reset cleanup - flushing " "NVME Req now. hba_flag x%x oxid x%x\n", phba->hba_flag, ctxp->oxid); @@ -3312,7 +2863,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, if (abts_wqeq->iocb_flag & LPFC_DRIVER_ABORTED) { spin_unlock_irqrestore(&phba->hbalock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6164 Outstanding NVME I/O Abort Request " "still pending on oxid x%x\n", ctxp->oxid); @@ -3326,35 +2877,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, /* Ready - mark outstanding as aborted by driver. */ abts_wqeq->iocb_flag |= LPFC_DRIVER_ABORTED; - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(abts_wqe, 0, sizeof(*abts_wqe)); - - /* word 3 */ - bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); - - /* word 7 */ - bf_set(wqe_ct, &abts_wqe->abort_cmd.wqe_com, 0); - bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - - /* word 8 - tell the FW to abort the IO associated with this - * outstanding exchange ID. - */ - abts_wqe->abort_cmd.wqe_com.abort_tag = ctxp->wqeq->sli4_xritag; - - /* word 9 - this is the iotag for the abts_wqe completion. */ - bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com, - abts_wqeq->iotag); - - /* word 10 */ - bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - /* word 11 */ - bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + lpfc_nvme_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx; @@ -3378,7 +2901,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, ctxp->flag &= ~LPFC_NVMET_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); lpfc_sli_release_iocbq(phba, abts_wqeq); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6166 Failed ABORT issue_wqe with status x%x " "for oxid x%x.\n", rc, ctxp->oxid); @@ -3403,7 +2926,7 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, } if (ctxp->state == LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6417 NVMET ABORT ctx freed %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); rc = WQE_BUSY; @@ -3441,7 +2964,7 @@ aerr: spin_unlock_irqrestore(&ctxp->ctxlock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6135 Failed to Issue ABTS for oxid x%x. Status x%x " "(%x)\n", ctxp->oxid, rc, released); @@ -3465,7 +2988,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, ctxp->state = LPFC_NVMET_STE_LS_ABORT; ctxp->entry_cnt++; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6418 NVMET LS abort state mismatch " "IO x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); @@ -3477,7 +3000,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, /* Issue ABTS for this WQE based on iotag */ ctxp->wqeq = lpfc_sli_get_iocbq(phba); if (!ctxp->wqeq) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6068 Abort failed: No wqeqs: " "xri: x%x\n", xri); /* No failure to an ABTS request. */ @@ -3508,7 +3031,476 @@ out: abts_wqeq->context3 = NULL; lpfc_sli_release_iocbq(phba, abts_wqeq); kfree(ctxp); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6056 Failed to Issue ABTS. Status x%x\n", rc); return 0; } +#endif + +/** + * lpfc_sli4_nvmet_xri_aborted - Fast-path process of nvmet xri abort + * @phba: pointer to lpfc hba data structure. + * @axri: pointer to the nvmet xri abort wcqe structure. + * + * This routine is invoked by the worker thread to process a SLI4 fast-path + * NVMET aborted xri. + **/ +void +lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri) +{ +#ifdef BUILD_NVMET_FC + uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); + uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); + struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_tgt_fcp_req *req = NULL; + struct lpfc_nodelist *ndlp; + unsigned long iflag = 0; + int rrq_empty = 0; + bool released = false; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6317 XB aborted xri x%x rxid x%x\n", xri, rxid); + + if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) + return; + + if (phba->targetport) { + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + atomic_inc(&tgtp->xmt_fcp_xri_abort_cqe); + } + + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_for_each_entry_safe(ctxp, next_ctxp, + &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, + list) { + if (ctxp->ctxbuf->sglq->sli4_xritag != xri) + continue; + + spin_lock(&ctxp->ctxlock); + /* Check if we already received a free context call + * and we have completed processing an abort situation. + */ + if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && + !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { + list_del_init(&ctxp->list); + released = true; + } + ctxp->flag &= ~LPFC_NVMET_XBUSY; + spin_unlock(&ctxp->ctxlock); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + + rrq_empty = list_empty(&phba->active_rrq_list); + spin_unlock_irqrestore(&phba->hbalock, iflag); + ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || + (ndlp->nlp_state == NLP_STE_MAPPED_NODE))) { + lpfc_set_rrq_active(phba, ndlp, + ctxp->ctxbuf->sglq->sli4_lxritag, + rxid, 1); + lpfc_sli4_abts_err_handler(phba, ndlp, axri); + } + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6318 XB aborted oxid x%x flg x%x (%x)\n", + ctxp->oxid, ctxp->flag, released); + if (released) + lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); + + if (rrq_empty) + lpfc_worker_wake_up(phba); + return; + } + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_unlock_irqrestore(&phba->hbalock, iflag); + + ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri); + if (ctxp) { + /* + * Abort already done by FW, so BA_ACC sent. + * However, the transport may be unaware. + */ + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6323 NVMET Rcv ABTS xri x%x ctxp state x%x " + "flag x%x oxid x%x rxid x%x\n", + xri, ctxp->state, ctxp->flag, ctxp->oxid, + rxid); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= LPFC_NVMET_ABTS_RCV; + ctxp->state = LPFC_NVMET_STE_ABORT; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + req = &ctxp->ctx.fcp_req; + if (req) + nvmet_fc_rcv_fcp_abort(phba->targetport, req); + } +#endif +} + +int +lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + struct fc_frame_header *fc_hdr) +{ +#ifdef BUILD_NVMET_FC +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_hba *phba = vport->phba; + struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct nvmefc_tgt_fcp_req *rsp; + uint32_t sid; + uint16_t oxid, xri; + unsigned long iflag = 0; + + sid = sli4_sid_from_fc_hdr(fc_hdr); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); + + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_for_each_entry_safe(ctxp, next_ctxp, + &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, + list) { + if (ctxp->oxid != oxid || ctxp->sid != sid) + continue; + + xri = ctxp->ctxbuf->sglq->sli4_xritag; + + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_unlock_irqrestore(&phba->hbalock, iflag); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= LPFC_NVMET_ABTS_RCV; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6319 NVMET Rcv ABTS:acc xri x%x\n", + xri); + + rsp = &ctxp->ctx.fcp_req; + nvmet_fc_rcv_fcp_abort(phba->targetport, rsp); + + /* Respond with BA_ACC accordingly */ + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_unlock_irqrestore(&phba->hbalock, iflag); + + /* check the wait list */ + if (phba->sli4_hba.nvmet_io_wait_cnt) { + struct rqb_dmabuf *nvmebuf; + struct fc_frame_header *fc_hdr_tmp; + u32 sid_tmp; + u16 oxid_tmp; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); + + /* match by oxid and s_id */ + list_for_each_entry(nvmebuf, + &phba->sli4_hba.lpfc_nvmet_io_wait_list, + hbuf.list) { + fc_hdr_tmp = (struct fc_frame_header *) + (nvmebuf->hbuf.virt); + oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id); + sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp); + if (oxid_tmp != oxid || sid_tmp != sid) + continue; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6321 NVMET Rcv ABTS oxid x%x from x%x " + "is waiting for a ctxp\n", + oxid, sid); + + list_del_init(&nvmebuf->hbuf.list); + phba->sli4_hba.nvmet_io_wait_cnt--; + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock, + iflag); + + /* free buffer since already posted a new DMA buffer to RQ */ + if (found) { + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + /* Respond with BA_ACC accordingly */ + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + } + + /* check active list */ + ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid); + if (ctxp) { + xri = ctxp->ctxbuf->sglq->sli4_xritag; + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x " + "flag x%x state x%x\n", + ctxp->oxid, xri, ctxp->flag, ctxp->state); + + if (ctxp->flag & LPFC_NVMET_TNOTIFY) { + /* Notify the transport */ + nvmet_fc_rcv_fcp_abort(phba->targetport, + &ctxp->ctx.fcp_req); + } else { + cancel_work_sync(&ctxp->ctxbuf->defer_work); + spin_lock_irqsave(&ctxp->ctxlock, iflag); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + + lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n", + oxid, raw_smp_processor_id(), 1); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid); + + /* Respond with BA_RJT accordingly */ + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); +#endif +#endif + return 0; +} + +#ifdef BUILD_NVMET_FC +static void +lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, + struct lpfc_nvmet_rcv_ctx *ctxp) +{ + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; + struct lpfc_iocbq *next_nvmewqeq; + unsigned long iflags; + struct lpfc_wcqe_complete wcqe; + struct lpfc_wcqe_complete *wcqep; + + pring = wq->pring; + wcqep = &wcqe; + + /* Fake an ABORT error code back to cmpl routine */ + memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete)); + bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT); + wcqep->parameter = IOERR_ABORT_REQUESTED; + + spin_lock_irqsave(&pring->ring_lock, iflags); + list_for_each_entry_safe(nvmewqeq, next_nvmewqeq, + &wq->wqfull_list, list) { + if (ctxp) { + /* Checking for a specific IO to flush */ + if (nvmewqeq->context2 == ctxp) { + list_del(&nvmewqeq->list); + spin_unlock_irqrestore(&pring->ring_lock, + iflags); + lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, + wcqep); + return; + } + continue; + } else { + /* Flush all IOs */ + list_del(&nvmewqeq->list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep); + spin_lock_irqsave(&pring->ring_lock, iflags); + } + } + if (!ctxp) + wq->q_flag &= ~HBA_NVMET_WQFULL; + spin_unlock_irqrestore(&pring->ring_lock, iflags); +} +#endif + +void +lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, + struct lpfc_queue *wq) +{ +#ifdef BUILD_NVMET_FC +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; + struct lpfc_nvmet_rcv_ctx *ctxp; + unsigned long iflags; + int rc; + + /* + * Some WQE slots are available, so try to re-issue anything + * on the WQ wqfull_list. + */ + pring = wq->pring; + spin_lock_irqsave(&pring->ring_lock, iflags); + while (!list_empty(&wq->wqfull_list)) { + list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq, + list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + ctxp = (struct lpfc_nvmet_rcv_ctx *)nvmewqeq->context2; + rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); + spin_lock_irqsave(&pring->ring_lock, iflags); + if (rc == -EBUSY) { + /* WQ was full again, so put it back on the list */ + list_add(&nvmewqeq->list, &wq->wqfull_list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + return; + } + if (rc == WQE_SUCCESS) { +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_cmd_nvme) { + if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) + ctxp->ts_status_wqput = ktime_get_ns(); + else + ctxp->ts_data_wqput = ktime_get_ns(); + } +#endif + } else { + WARN_ON(rc); + } + } + wq->q_flag &= ~HBA_NVMET_WQFULL; + spin_unlock_irqrestore(&pring->ring_lock, iflags); + +#endif +#endif +} + +#ifdef BUILD_NVMET_FC +static void +lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) +{ +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; + struct lpfc_hba *phba = ctxp->phba; + struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; + struct lpfc_nvmet_tgtport *tgtp; + uint32_t *payload, qno; + uint32_t rc; + unsigned long iflags; + + if (!nvmebuf) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6159 process_rcv_fcp_req, nvmebuf is NULL, " + "oxid: x%x flg: x%x state: x%x\n", + ctxp->oxid, ctxp->flag, ctxp->state); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + return; + } + + if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6324 IO oxid x%x aborted\n", + ctxp->oxid); + return; + } + + payload = (uint32_t *)(nvmebuf->dbuf.virt); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + ctxp->flag |= LPFC_NVMET_TNOTIFY; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_isr_cmd) + ctxp->ts_cmd_nvme = ktime_get_ns(); +#endif + /* + * The calling sequence should be: + * nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done + * lpfc_nvmet_xmt_fcp_op_cmp should free the allocated ctxp. + * When we return from nvmet_fc_rcv_fcp_req, all relevant info + * the NVME command / FC header is stored. + * A buffer has already been reposted for this IO, so just free + * the nvmebuf. + */ + rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->ctx.fcp_req, + payload, ctxp->size); + /* Process FCP command */ + if (rc == 0) { + atomic_inc(&tgtp->rcv_fcp_cmd_out); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) || + (nvmebuf != ctxp->rqb_buffer)) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; + } + ctxp->rqb_buffer = NULL; + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ + return; + } + + /* Processing of FCP command is deferred */ + if (rc == -EOVERFLOW) { + lpfc_nvmeio_data(phba, "NVMET RCV BUSY: xri x%x sz %d " + "from %06x\n", + ctxp->oxid, ctxp->size, ctxp->sid); + atomic_inc(&tgtp->rcv_fcp_cmd_out); + atomic_inc(&tgtp->defer_fod); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; + } + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + /* + * Post a replacement DMA buffer to RQ and defer + * freeing rcv buffer till .defer_rcv callback + */ + qno = nvmebuf->idx; + lpfc_post_rq_buffer( + phba, phba->sli4_hba.nvmet_mrq_hdr[qno], + phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); + return; + } + ctxp->flag &= ~LPFC_NVMET_TNOTIFY; + atomic_inc(&tgtp->rcv_fcp_cmd_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", + ctxp->oxid, rc, + atomic_read(&tgtp->rcv_fcp_cmd_in), + atomic_read(&tgtp->rcv_fcp_cmd_out), + atomic_read(&tgtp->xmt_fcp_release)); + lpfc_nvmeio_data(phba, "NVMET FCP DROP: xri x%x sz %d from %06x\n", + ctxp->oxid, ctxp->size, ctxp->sid); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); +#endif +} + +static void +lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *work) +{ +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_nvmet_ctxbuf *ctx_buf = + container_of(work, struct lpfc_nvmet_ctxbuf, defer_work); + + lpfc_nvmet_process_rcv_fcp_req(ctx_buf); +#endif +} +#endif + diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 8ff67deac..e80f18394 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -21,7 +21,9 @@ * included with this package. * ********************************************************************/ -#define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ +#define LPFC_NVMET_MIN_SEGS 16 +#define LPFC_NVMET_DEFAULT_SEGS 64 /* 256K IOs */ +#define LPFC_NVMET_MAX_SEGS 510 #define LPFC_NVMET_RQE_MIN_POST 128 #define LPFC_NVMET_RQE_DEF_POST 512 #define LPFC_NVMET_RQE_DEF_COUNT 2048 @@ -90,31 +92,22 @@ struct lpfc_nvmet_tgtport { atomic_t defer_wqfull; }; -struct lpfc_nvmet_ctx_info { - struct list_head nvmet_ctx_list; - spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ - struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; - struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; - uint16_t nvmet_ctx_list_cnt; - char pad[16]; /* pad to a cache-line */ -}; - -/* This retrieves the context info associated with the specified cpu / mrq */ -#define lpfc_get_ctx_list(phba, cpu, mrq) \ - (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) - struct lpfc_nvmet_rcv_ctx { +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_FC)) union { +#if defined(BUILD_NVME_PLUS) + struct nvmefc_ls_rsp ls_req; +#else struct nvmefc_tgt_ls_req ls_req; +#endif struct nvmefc_tgt_fcp_req fcp_req; } ctx; +#endif struct list_head list; struct lpfc_hba *phba; struct lpfc_iocbq *wqeq; struct lpfc_iocbq *abort_wqeq; - dma_addr_t txrdy_phys; spinlock_t ctxlock; /* protect flag access */ - uint32_t *txrdy; uint32_t sid; uint32_t offset; uint16_t oxid; @@ -158,3 +151,17 @@ struct lpfc_nvmet_rcv_ctx { uint64_t ts_status_nvme; #endif }; + +struct lpfc_nvmet_ctx_info { + struct list_head nvmet_ctx_list; + spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ + struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; + struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; + uint16_t nvmet_ctx_list_cnt; + char pad[16]; /* pad to a cache-line */ +}; + +/* This retrieves the context info associated with the specified cpu / mrq */ +#define lpfc_get_ctx_list(phba, cpu, mrq) \ + (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) + diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index cbab15d29..c33f97f8b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -23,10 +23,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -80,6 +78,18 @@ lpfc_rport_data_from_scsi_device(struct scsi_device *sdev) return (struct lpfc_rport_data *)sdev->hostdata; } +static struct lpfc_external_dif_support * +lpfc_external_dif_match(struct lpfc_vport *vport, uint64_t lun, uint32_t sid); + +static int +lpfc_external_dif(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + struct lpfc_nodelist *ndlp, uint8_t *cdb_ptr); +static void +lpfc_external_dif_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + struct lpfc_iocbq *pIocbOut); +extern int +lpfc_issue_scsi_inquiry(struct lpfc_vport *, + struct lpfc_nodelist *, uint32_t); static void lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static void @@ -87,6 +97,33 @@ lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc); +#ifdef BUILD_ASMIO +static inline unsigned +lpfc_cmd_blksize(struct scsi_cmnd *sc) +{ + return scsi_prot_interval(sc); +} + +#define LPFC_CHECK_PROTECT_GUARD 1 +#define LPFC_CHECK_PROTECT_REF 2 +static inline unsigned +lpfc_cmd_protect(struct scsi_cmnd *sc, int flag) +{ + if (flag == LPFC_CHECK_PROTECT_GUARD) + return (scsi_prot_flagged(sc, SCSI_PROT_GUARD_CHECK)); + if (flag == LPFC_CHECK_PROTECT_REF) + return (scsi_prot_flagged(sc, SCSI_PROT_REF_CHECK)); + return 0; +} + +static inline unsigned +lpfc_cmd_guard_csum(struct scsi_cmnd *sc) +{ + return (scsi_prot_flagged(sc, SCSI_PROT_IP_CHECKSUM)); +} + +#else + static inline unsigned lpfc_cmd_blksize(struct scsi_cmnd *sc) { @@ -110,6 +147,7 @@ lpfc_cmd_guard_csum(struct scsi_cmnd *sc) return 1; return 0; } +#endif /** * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. @@ -134,21 +172,21 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, /** * lpfc_update_stats - Update statistical data for the command completion - * @phba: Pointer to HBA object. + * @vport: The virtual port on which this call is executing. * @lpfc_cmd: lpfc scsi command object pointer. * * This function is called when there is a command completion and this * function updates the statistical data for the command completion. **/ static void -lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) +lpfc_update_stats(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) { + struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata; struct lpfc_nodelist *pnode; struct scsi_cmnd *cmd = lpfc_cmd->pCmd; unsigned long flags; - struct Scsi_Host *shost = cmd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); unsigned long latency; int i; @@ -188,6 +226,7 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) spin_unlock_irqrestore(shost->host_lock, flags); } + /** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread * @phba: The Hba for which this call is being executed. @@ -293,21 +332,40 @@ void lpfc_scsi_dev_block(struct lpfc_hba *phba) { struct lpfc_vport **vports; + struct lpfc_vport *vport; struct Scsi_Host *shost; struct scsi_device *sdev; struct fc_rport *rport; + struct lpfc_external_dif_support *dp; + unsigned long flags; int i; vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); + vport = vports[i]; + shost = lpfc_shost_from_vport(vport); shost_for_each_device(sdev, shost) { rport = starget_to_rport(scsi_target(sdev)); fc_remote_port_delete(rport); } + + /* + * Cleanup all External DIF paths on this vport. They + * will need to be revalidated if the NPort comes back. + */ + spin_lock_irqsave(&vport->external_dif_lock, flags); + list_for_each_entry(dp, &vport->external_dif_list, + listentry) { + lpfc_edsm_set_state(vport, dp, + LPFC_EDSM_NEEDS_INQUIRY); + } + spin_unlock_irqrestore(&vport->external_dif_lock, + flags); + } lpfc_destroy_vport_work_array(phba, vports); + } /** @@ -366,7 +424,6 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) break; } - /* Allocate iotag for psb->cur_iocbq. */ iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); if (iotag == 0) { @@ -474,6 +531,10 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) return; + /* may be called before queues established if hba_setup fails */ + if (!phba->sli4_hba.hdwq) + return; + spin_lock_irqsave(&phba->hbalock, iflag); for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; @@ -481,7 +542,7 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, &qp->lpfc_abts_io_buf_list, list) { - if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) + if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME) continue; if (psb->rdata && psb->rdata->pnode && @@ -528,13 +589,15 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, list_del_init(&psb->list); psb->flags &= ~LPFC_SBUF_XBUSY; psb->status = IOSTAT_SUCCESS; - if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) { +#if (IS_ENABLED(CONFIG_NVME_FC)) + if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME) { qp->abts_nvme_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); lpfc_sli4_nvme_xri_aborted(phba, axri, psb); return; } +#endif qp->abts_scsi_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); @@ -641,7 +704,18 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct fcp_cmd_rsp_buf *tmp = NULL; cpu = raw_smp_processor_id(); - if (cmnd && phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) { + + /* Lookup Hardware Queue index based on fcp_io_sched module parameter + * and if SCSI mq is turned on. + */ +#if (KERNEL_MAJOR > 4) || defined(BUILD_RHEL8) + if (cmnd && phba->cfg_enable_scsi_mq && + (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ)) { +#else + if (cmnd && shost_use_blk_mq(cmnd->device->host) && + phba->cfg_enable_scsi_mq && + (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ)) { +#endif tag = blk_mq_unique_tag(cmnd->request); idx = blk_mq_unique_tag_to_hwq(tag); } else { @@ -665,6 +739,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, lpfc_cmd->timeout = 0; lpfc_cmd->flags = 0; lpfc_cmd->start_time = jiffies; + lpfc_cmd->edifp = NULL; lpfc_cmd->waitq = NULL; lpfc_cmd->cpu = cpu; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -721,7 +796,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, iocb->ulpLe = 1; iocb->ulpClass = CLASS3; - if (lpfc_ndlp_check_qdepth(phba, ndlp) && lpfc_cmd) { + if (lpfc_ndlp_check_qdepth(phba, ndlp)) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; } @@ -758,6 +833,7 @@ lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb) { unsigned long iflag = 0; + psb->edifp = NULL; psb->seg_cnt = 0; psb->prot_seg_cnt = 0; @@ -784,6 +860,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb) struct lpfc_sli4_hdw_queue *qp; unsigned long iflag = 0; + psb->edifp = NULL; psb->seg_cnt = 0; psb->prot_seg_cnt = 0; @@ -813,10 +890,29 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) if ((psb->flags & LPFC_SBUF_BUMP_QDEPTH) && psb->ndlp) atomic_dec(&psb->ndlp->cmd_pending); - psb->flags &= ~LPFC_SBUF_BUMP_QDEPTH; + psb->flags &= ~(LPFC_SBUF_NORMAL_DIF | LPFC_SBUF_PASS_DIF | + LPFC_SBUF_BUMP_QDEPTH); phba->lpfc_release_scsi_buf(phba, psb); } +/** + * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB + * @data: A pointer to the immediate command data portion of the IOCB. + * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. + * + * The routine copies the entire FCP command from @fcp_cmnd to @data while + * byte swapping the data to big endian format for transmission on the wire. + **/ +static void +lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) +{ + int i, j; + for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); + i += sizeof(uint32_t), j++) { + ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); + } +} + /** * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. @@ -867,11 +963,11 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9064 BLKGRD: %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9064 BLKGRD: %s: Too many sg segments" + " from dma_map_sg. Config %d, seg_cnt" + " %d\n", __func__, phba->cfg_sg_seg_cnt, + lpfc_cmd->seg_cnt); WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); @@ -953,9 +1049,42 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * we need to set word 4 of IOCB here */ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); return 0; } +/** + * lpfc_scsi_get_prot_op - Gets the SCSI defined protection data operation + * @sc: The SCSI Layer structure for the IO in question. + * + * This routine calls the SCSI Layer to get the protectio data operation + * associated with the specified IO. Then, if this is an IO effected by an + * External DIF device, the protection operation is adjusted accordingly. + * + * Returns the SCSI defined protection data operation + **/ +uint32_t +lpfc_scsi_get_prot_op(struct scsi_cmnd *sc) +{ + struct lpfc_io_buf *lpfc_cmd; + uint32_t op = scsi_get_prot_op(sc); + + lpfc_cmd = (struct lpfc_io_buf *)sc->host_scribble; + if (lpfc_cmd->flags & LPFC_SBUF_NORMAL_DIF) { + if (sc->sc_data_direction == DMA_FROM_DEVICE) + op = SCSI_PROT_READ_STRIP; + else if (sc->sc_data_direction == DMA_TO_DEVICE) + op = SCSI_PROT_WRITE_INSERT; + } else if (lpfc_cmd->flags & LPFC_SBUF_PASS_DIF) { + if (sc->sc_data_direction == DMA_FROM_DEVICE) + op = SCSI_PROT_READ_PASS; + else if (sc->sc_data_direction == DMA_TO_DEVICE) + op = SCSI_PROT_WRITE_PASS; + } + return op; +} + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS /* Return BG_ERR_INIT if error injection is detected by Initiator */ @@ -989,7 +1118,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct scsi_dif_tuple *src = NULL; struct lpfc_nodelist *ndlp; struct lpfc_rport_data *rdata; - uint32_t op = scsi_get_prot_op(sc); + uint32_t op = lpfc_scsi_get_prot_op(sc); uint32_t blksize; uint32_t numblks; sector_t lba; @@ -1061,7 +1190,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * inserted in middle of the IO. */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "9076 BLKGRD: Injecting reftag error: " "write lba x%lx + x%x oldrefTag x%x\n", (unsigned long)lba, blockoff, @@ -1111,7 +1241,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_TGT | BG_ERR_CHECK; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9078 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1132,7 +1262,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9077 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1159,7 +1289,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9079 BLKGRD: Injecting reftag error: " "read lba x%lx\n", (unsigned long)lba); break; @@ -1181,7 +1311,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * inserted in middle of the IO. */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "9080 BLKGRD: Injecting apptag error: " "write lba x%lx + x%x oldappTag x%x\n", (unsigned long)lba, blockoff, @@ -1230,7 +1361,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_TGT | BG_ERR_CHECK; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0813 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1251,7 +1382,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0812 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1278,7 +1409,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0814 BLKGRD: Injecting apptag error: " "read lba x%lx\n", (unsigned long)lba); break; @@ -1313,7 +1444,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc |= BG_ERR_TGT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0817 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1335,7 +1466,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0816 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1363,7 +1494,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0818 BLKGRD: Injecting guard error: " "read lba x%lx\n", (unsigned long)lba); } @@ -1392,7 +1523,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint8_t ret = 0; if (lpfc_cmd_guard_csum(sc)) { - switch (scsi_get_prot_op(sc)) { + switch (lpfc_scsi_get_prot_op(sc)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: *rxop = BG_OP_IN_NODIF_OUT_CSUM; @@ -1413,15 +1544,15 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, case SCSI_PROT_NORMAL: default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9063 BLKGRD: Bad op/guard:%d/IP combination\n", - scsi_get_prot_op(sc)); + lpfc_scsi_get_prot_op(sc)); ret = 1; break; } } else { - switch (scsi_get_prot_op(sc)) { + switch (lpfc_scsi_get_prot_op(sc)) { case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: *rxop = BG_OP_IN_CRC_OUT_NODIF; @@ -1442,9 +1573,9 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, case SCSI_PROT_NORMAL: default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9075 BLKGRD: Bad op/guard:%d/CRC combination\n", - scsi_get_prot_op(sc)); + lpfc_scsi_get_prot_op(sc)); ret = 1; break; } @@ -1472,7 +1603,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint8_t ret = 0; if (lpfc_cmd_guard_csum(sc)) { - switch (scsi_get_prot_op(sc)) { + switch (lpfc_scsi_get_prot_op(sc)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: *rxop = BG_OP_IN_NODIF_OUT_CRC; @@ -1497,7 +1628,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, } } else { - switch (scsi_get_prot_op(sc)) { + switch (lpfc_scsi_get_prot_op(sc)) { case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: *rxop = BG_OP_IN_CSUM_OUT_NODIF; @@ -1728,7 +1859,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgde = scsi_sglist(sc); if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9020 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; @@ -1840,7 +1971,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return num_bde + 1; if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9065 BLKGRD:%s Invalid data segment\n", __func__); return 0; @@ -1903,8 +2034,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, reftag += protgrp_blks; } else { /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9054 BLKGRD: bug in %s\n", __func__); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9054 BLKGRD: bug in %s\n", __func__); } } while (!alldone); @@ -2154,7 +2285,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgde = scsi_sglist(sc); if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9082 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; @@ -2307,7 +2438,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return num_sge + 1; if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9086 BLKGRD:%s Invalid data segment\n", __func__); return 0; @@ -2412,8 +2543,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, reftag += protgrp_blks; } else { /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9085 BLKGRD: bug in %s\n", __func__); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9085 BLKGRD: bug in %s\n", __func__); } } while (!alldone); @@ -2438,7 +2569,7 @@ static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) { int ret = LPFC_PG_TYPE_INVALID; - unsigned char op = scsi_get_prot_op(sc); + unsigned char op = lpfc_scsi_get_prot_op(sc); switch (op) { case SCSI_PROT_READ_STRIP: @@ -2453,7 +2584,7 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) break; default: if (phba) - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9021 Unsupported protection op:%d\n", op); break; @@ -2483,12 +2614,12 @@ lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, /* Check if there is protection data on the wire */ if (sc->sc_data_direction == DMA_FROM_DEVICE) { /* Read check for protection data */ - if (scsi_get_prot_op(sc) == SCSI_PROT_READ_INSERT) + if (lpfc_scsi_get_prot_op(sc) == SCSI_PROT_READ_INSERT) return fcpdl; } else { /* Write check for protection data */ - if (scsi_get_prot_op(sc) == SCSI_PROT_WRITE_STRIP) + if (lpfc_scsi_get_prot_op(sc) == SCSI_PROT_WRITE_STRIP) return fcpdl; } @@ -2527,7 +2658,6 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, int prot_group_type = 0; int fcpdl; int ret = 1; - struct lpfc_vport *vport = phba->pport; /* * Start the lpfc command prep by bumping the bpl beyond fcp_cmnd @@ -2617,7 +2747,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, scsi_dma_unmap(scsi_cmnd); lpfc_cmd->seg_cnt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9022 Unexpected protection group %i\n", prot_group_type); return 2; @@ -2649,7 +2779,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, * length for DIF */ if (iocb_cmd->un.fcpi.fcpi_XRdy && - (fcpdl < vport->cfg_first_burst_size)) + (fcpdl < lpfc_cmd->ndlp->first_burst)) iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl; return 0; @@ -2661,7 +2791,7 @@ err: scsi_prot_sg_count(scsi_cmnd), scsi_cmnd->sc_data_direction); - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9023 Cannot setup S/G List for HBA" "IO segs %d/%d BPL %d SCSI %d: %d %d\n", lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, @@ -2684,7 +2814,29 @@ lpfc_bg_crc(uint8_t *data, int count) uint16_t crc = 0; uint16_t x; +#if defined(BUILD_CITRIX_XS) + uint16_t poly = 0x8BB7L; + unsigned int poly_length = 16; + unsigned int i, j, fb; + + for (i = 0; i < count; i += 2) { + + x = (data[i] << 8) | data[i+1]; + + /* serial shift register implementation */ + for (j = 0; j < poly_length; j++) { + fb = ((x & 0x8000L) == 0x8000L) ^ ((crc & + 0x8000L) == 0x8000L); + x <<= 1; + crc <<= 1; + if (fb) + crc ^= poly; + } + } + +#else crc = crc_t10dif(data, count); +#endif x = cpu_to_be16(crc); return x; } @@ -2729,7 +2881,7 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) guard_tag = 0; /* First check to see if there is protection data to examine */ - prot = scsi_get_prot_op(cmd); + prot = lpfc_scsi_get_prot_op(cmd); if ((prot == SCSI_PROT_READ_STRIP) || (prot == SCSI_PROT_WRITE_INSERT) || (prot == SCSI_PROT_NORMAL)) @@ -2768,8 +2920,8 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * First check to see if a protection data * check is valid */ - if ((src->ref_tag == T10_PI_REF_ESCAPE) || - (src->app_tag == T10_PI_APP_ESCAPE)) { + if ((src->ref_tag == 0xffffffff) || + (src->app_tag == 0xffff)) { start_ref_tag++; goto skipit; } @@ -2990,7 +3142,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, cmd->sense_buffer[10] = 0x80; /* Validity bit */ /* bghm is a "on the wire" FC frame based count */ - switch (scsi_get_prot_op(cmd)) { + switch (lpfc_scsi_get_prot_op(cmd)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: bghm /= cmd->device->sector_size; @@ -3085,11 +3237,12 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (!phba->cfg_xpsgl && lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:" - " %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9074 BLKGRD:" + " %s: Too many sg segments from " + "dma_map_sg. Config %d, seg_cnt %d\n", + __func__, phba->cfg_sg_seg_cnt, + lpfc_cmd->seg_cnt); WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); @@ -3265,7 +3418,6 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, int prot_group_type = 0; int fcpdl; int ret = 1; - struct lpfc_vport *vport = phba->pport; /* * Start the lpfc command prep by bumping the sgl beyond fcp_cmnd @@ -3366,14 +3518,14 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, scsi_dma_unmap(scsi_cmnd); lpfc_cmd->seg_cnt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9083 Unexpected protection group %i\n", prot_group_type); return 2; } } - switch (scsi_get_prot_op(scsi_cmnd)) { + switch (lpfc_scsi_get_prot_op(scsi_cmnd)) { case SCSI_PROT_WRITE_STRIP: case SCSI_PROT_READ_STRIP: lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF_STRIP; @@ -3402,7 +3554,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, * length for DIF */ if (iocb_cmd->un.fcpi.fcpi_XRdy && - (fcpdl < vport->cfg_first_burst_size)) + (fcpdl < lpfc_cmd->ndlp->first_burst)) iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl; /* @@ -3422,7 +3574,7 @@ err: scsi_prot_sg_count(scsi_cmnd), scsi_cmnd->sc_data_direction); - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9084 Cannot setup S/G List for HBA" "IO segs %d/%d SGL %d SCSI %d: %d %d\n", lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, @@ -3591,6 +3743,235 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) psb->pCmd->sc_data_direction); } +uint32_t +lpfc_edsm_process_inq_data_chg(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd) +{ + struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; + struct lpfc_external_dif_support *dp = lpfc_cmd->edifp; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *pnode; + unsigned long flags; + int rc; + + rdata = lpfc_cmd->rdata; + pnode = rdata->pnode; + + spin_lock_irqsave(&vport->external_dif_lock, flags); + if (dp == NULL) { + dp = lpfc_external_dif_match(vport, cmnd->device->lun, + pnode->nlp_sid); + if (dp == NULL) { + spin_unlock_irqrestore(&vport->external_dif_lock, + flags); + return DID_OK; + } + } + rc = lpfc_issue_scsi_inquiry(vport, pnode, dp->lun); + if (rc == 0) + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_PATH_CHECK); + else + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_NEEDS_INQUIRY); + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + dp->err3f_cnt++; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0913 INQ Data Change: Data: " + "%x %x %x", + cmnd->cmnd[0], + be32_to_cpu(fcpcmd->fcpDl), + lpfc_cmd->cur_iocbq.sli4_xritag); + + /* Convert to retryable err */ + return DID_ERROR; +} + +uint32_t +lpfc_edsm_process_data_phase(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd) +{ + struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; + struct lpfc_external_dif_support *dp = lpfc_cmd->edifp; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *pnode; + unsigned long flags; + int rc; + + rdata = lpfc_cmd->rdata; + pnode = rdata->pnode; + + spin_lock_irqsave(&vport->external_dif_lock, flags); + if (dp == NULL) { + dp = lpfc_external_dif_match(vport, cmnd->device->lun, + pnode->nlp_sid); + if (dp == NULL) { + spin_unlock_irqrestore(&vport->external_dif_lock, + flags); + return DID_OK; + } + } + /* + * Extra check in case we dropped the + * LPFC_ASC_TARGET_CHANGED error. + */ + if (dp->state != LPFC_EDSM_PATH_CHECK && + dp->state != LPFC_EDSM_PATH_STANDBY) { + rc = lpfc_issue_scsi_inquiry(vport, pnode, dp->lun); + if (rc == 0) + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_PATH_CHECK); + else + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_NEEDS_INQUIRY); + } + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + dp->err4b_cnt++; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0914 Data Phase Err: Data: " + "%x %x %x", + cmnd->cmnd[0], + be32_to_cpu(fcpcmd->fcpDl), + lpfc_cmd->cur_iocbq.sli4_xritag); + + /* Convert to retryable err */ + return DID_ERROR; +} + +/** + * lpfc_unblock_requests: allow further commands from being queued. + * For single vport, just call scsi_unblock_requests on physical port. + * For multiple vports sent scsi_unblock_requests for all the vports. + */ +void +lpfc_unblock_requests(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + struct Scsi_Host *shost; + int i; + + if (phba->sli_rev == LPFC_SLI_REV4 && + !phba->sli4_hba.max_cfg_param.vpi_used) { + shost = lpfc_shost_from_vport(phba->pport); + scsi_unblock_requests(shost); + return; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_unblock_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** + * lpfc_block_requests: prevent further commands from being queued. + * For single vport, just call scsi_block_requests on physical port. + * For multiple vports sent scsi_block_requests for all the vports. + */ +void +lpfc_block_requests(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + struct Scsi_Host *shost; + int i; + + if (atomic_read(&phba->cmf_stop_io)) + return; + + if (phba->sli_rev == LPFC_SLI_REV4 && + !phba->sli4_hba.max_cfg_param.vpi_used) { + shost = lpfc_shost_from_vport(phba->pport); + scsi_block_requests(shost); + return; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_block_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** + * lpfc_update_cmf_cmpl - Adjust CMF counters for IO completion + * @phba: The HBA for which this call is being executed. + * @time: The latency of the IO that completed (in ns) + * @size: The size of the IO that completed + * @shost: SCSI host the IO completed on (NULL for a NVME IO) + * + * The routine adjusts the various Burst and Bandwidth counters used in + * Congestion management and E2E. If time is set to LPFC_CGN_NOT_SENT, + * that means the IO was never issued to the HBA, so this routine is + * just being called to cleanup the counter from a previous + * lpfc_update_cmf_cmd call. + */ +int +lpfc_update_cmf_cmpl(struct lpfc_hba *phba, + uint64_t time, uint32_t size, struct Scsi_Host *shost) +{ + struct lpfc_cgn_stat *cgs; + + if (time != LPFC_CGN_NOT_SENT) { + /* lat is ns coming in, save latency in us */ + if (time < 1000) + time = 1; + else + time = (time + 500) / 1000; /* round it */ + + cgs = this_cpu_ptr(phba->cmf_stat); + atomic64_add(size, &cgs->rcv_bytes); + atomic64_add(time, &cgs->rx_latency); + atomic_inc(&cgs->rx_io_cnt); + } + return 0; +} + +/** + * lpfc_update_cmf_cmd - Adjust CMF counters for IO submission + * @phba: The HBA for which this call is being executed. + * @size: The size of the IO that will be issued + * + * The routine adjusts the various Burst and Bandwidth counters used in + * Congestion management and E2E. + */ +int +lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t size) +{ + uint64_t total; + struct lpfc_cgn_stat *cgs; + int cpu; + + /* At this point we are either LPFC_CFG_MANAGED or LPFC_CFG_MONITOR */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED && + phba->cmf_max_bytes_per_interval) { + total = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_read(&cgs->total_bytes); + } + if (total >= phba->cmf_max_bytes_per_interval) { + if (!atomic_xchg(&phba->cmf_bw_wait, 1)) { + lpfc_block_requests(phba); + phba->cmf_last_ts = + lpfc_calc_cmf_latency(phba); + } + atomic_inc(&phba->cmf_busy); + return -EBUSY; + } + if (size > atomic_read(&phba->rx_max_read_cnt)) + atomic_set(&phba->rx_max_read_cnt, size); + } + + cgs = this_cpu_ptr(phba->cmf_stat); + atomic64_add(size, &cgs->total_bytes); + return 0; +} + /** * lpfc_handler_fcp_err - FCP response handler * @vport: The virtual port for which this call is being executed. @@ -3612,12 +3993,15 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; + struct lpfc_external_dif_support *dp; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *pnode; uint32_t *lp; uint32_t host_status = DID_OK; uint32_t rsplen = 0; uint32_t fcpDl; uint32_t logit = LOG_FCP | LOG_FCP_ERROR; - + uint8_t asc, ascq; /* * If this is a task management command, there is no @@ -3632,17 +4016,17 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, if (resp_info & RSP_LEN_VALID) { rsplen = be32_to_cpu(fcprsp->rspRspLen); if (rsplen != 0 && rsplen != 4 && rsplen != 8) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "2719 Invalid response length: " - "tgt x%x lun x%llx cmnd x%x rsplen x%x\n", - cmnd->device->id, - cmnd->device->lun, cmnd->cmnd[0], - rsplen); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2719 Invalid response length: " + "tgt x%x lun x%llx cmnd x%x rsplen " + "x%x\n", cmnd->device->id, + cmnd->device->lun, cmnd->cmnd[0], + rsplen); host_status = DID_ERROR; goto out; } if (fcprsp->rspInfo3 != RSP_NO_FAILURE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2757 Protocol failure detected during " "processing of FCP I/O op: " "tgt x%x lun x%llx cmnd x%x rspInfo3 x%x\n", @@ -3775,7 +4159,80 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, scsi_set_resid(cmnd, scsi_bufflen(cmnd)); } - out: +out: + rdata = lpfc_cmd->rdata; + pnode = rdata->pnode; + if (pnode && (pnode->nlp_flag & NLP_EXTERNAL_DIF)) { + /* Is this an External DIF array? */ + dp = lpfc_cmd->edifp; + asc = cmnd->sense_buffer[12]; + ascq = cmnd->sense_buffer[13]; + /* Check for LOGICAL BLOCK GUARD CHECK / REF TAG failed */ + if (scsi_status == SAM_STAT_CHECK_CONDITION) { + if (dp && + (asc == LPFC_ASC_DIF_ERR) && + ((ascq == LPFC_ASCQ_GUARD_CHECK) || + (ascq == LPFC_ASCQ_REFTAG_CHECK))) { + host_status = DID_ERROR; + scsi_status = SAM_STAT_GOOD; + /* Convert to retryable err */ + } + + /* + * A Operation Condition Change error on an External DIF + * device indicates its in transition from one mode to + * another. + */ + if ((asc == LPFC_ASC_TARGET_CHANGED) && + (ascq == LPFC_ASCQ_INQUIRY_DATA)) { + host_status = + lpfc_edsm_process_inq_data_chg( + vport, lpfc_cmd); + if (host_status == DID_ERROR) + scsi_status = SAM_STAT_GOOD; + } + /* + * A Data Phase error on External DIF device indicates + * the IO was sent in the wrong mode. + */ + if ((asc == LPFC_ASC_DATA_PHASE_ERR) && + (ascq == LPFC_ASCQ_EDIF_MODE)) { + host_status = + lpfc_edsm_process_data_phase( + vport, lpfc_cmd); + if (host_status == DID_ERROR) + scsi_status = SAM_STAT_GOOD; + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "3031 FCP command x%x force ERROR " + "asc/ascq:x%x/x%x " + "xri x%x lba x%llx stat %d:%d\n", + cmnd->cmnd[0], asc, ascq, + lpfc_cmd->cur_iocbq.sli4_xritag, + (unsigned long long)scsi_get_lba(cmnd), + host_status, scsi_status); + /* + * If the scsi_status has been changed to SAM_STAT_GOOD, + * we need to massage the cmnd and remove all trace + * of the check condition. + */ + if (scsi_status == SAM_STAT_GOOD) { + /* Cleanup FCP response */ + fcprsp->rspStatus2 &= + ~(SNS_LEN_VALID | RESID_UNDER); + fcprsp->rspSnsLen = 0; + + /* resid must be 0 */ + scsi_set_resid(cmnd, 0); + + /* Get rid of any unwanted sense data */ + memset(cmnd->sense_buffer, 0, + SCSI_SENSE_BUFFERSIZE); + } + + } + } cmnd->result = host_status << 16 | scsi_status; lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb); } @@ -3805,17 +4262,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct Scsi_Host *shost; int idx; uint32_t logit = LOG_FCP; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - int cpu; -#endif + uint32_t lat; /* Guard against abort handler being called at same time */ spin_lock(&lpfc_cmd->buf_lock); /* Sanity check on return of outstanding command */ cmd = lpfc_cmd->pCmd; - if (!cmd) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + if (!cmd || !phba) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2621 IO completion: Not an active IO\n"); spin_unlock(&lpfc_cmd->buf_lock); return; @@ -3826,11 +4281,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { - cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq) - phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; - } + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); #endif shost = cmd->device->host; @@ -3874,7 +4326,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } #endif - if (lpfc_cmd->status) { + if (unlikely(lpfc_cmd->status)) { if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && (lpfc_cmd->result & IOERR_DRVR_MASK)) lpfc_cmd->status = IOSTAT_DRIVER_REJECT; @@ -3957,7 +4409,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED || lpfc_cmd->result == IOERR_TX_DMA_FAILED) && pIocbOut->iocb.unsli3.sli3_bg.bgstat) { - if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { + if (lpfc_scsi_get_prot_op(cmd) != + SCSI_PROT_NORMAL) { /* * This is a response for a BG enabled * cmd. Parse BG error @@ -4007,7 +4460,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, scsi_get_resid(cmd)); } - lpfc_update_stats(phba, lpfc_cmd); + lpfc_update_stats(vport, lpfc_cmd); + if (vport->cfg_max_scsicmpl_time && time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { @@ -4028,9 +4482,26 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->ts_cmd_start) { + lpfc_cmd->ts_isr_cmpl = pIocbIn->isr_timestamp; + lpfc_cmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_cmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_cmd); + } +#endif lpfc_cmd->pCmd = NULL; spin_unlock(&lpfc_cmd->buf_lock); + /* Check if IO qualified for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + cmd->sc_data_direction == DMA_FROM_DEVICE && + (scsi_sg_count(cmd))) { + /* Used when calculating average latency */ + lat = ktime_get_ns() - lpfc_cmd->rx_cmd_start; + lpfc_update_cmf_cmpl(phba, lat, scsi_bufflen(cmd), shost); + } + /* The sdev is not guaranteed to be valid post scsi_done upcall. */ cmd->scsi_done(cmd); @@ -4047,24 +4518,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_release_scsi_buf(phba, lpfc_cmd); } -/** - * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB - * @data: A pointer to the immediate command data portion of the IOCB. - * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. - * - * The routine copies the entire FCP command from @fcp_cmnd to @data while - * byte swapping the data to big endian format for transmission on the wire. - **/ -static void -lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) -{ - int i, j; - for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); - i += sizeof(uint32_t), j++) { - ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); - } -} - /** * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit * @vport: The virtual port for which this call is being executed. @@ -4074,7 +4527,7 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) * This routine initializes fcp_cmnd and iocb data structure from scsi command * to transfer for device with SLI3 interface spec. **/ -static void +static int lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, struct lpfc_nodelist *pnode) { @@ -4085,13 +4538,20 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); struct lpfc_sli4_hdw_queue *hdwq = NULL; int datadir = scsi_cmnd->sc_data_direction; - int idx; + int rc, idx; uint8_t *ptr; bool sli4; + bool scan_io; + uint8_t tmo; uint32_t fcpdl; +#ifndef NO_APEX + uint8_t fcp_priority = 0; + uint8_t pri; + uint32_t lun_index; +#endif if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return; + return 0; lpfc_cmd->fcp_rsp->rspSnsLen = 0; /* clear task management bits */ @@ -4107,7 +4567,37 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); } + /* Check if we want to make this IO an External DIF device */ + if (vport->phba->cfg_external_dif && + !(pnode->nlp_flag & NLP_SKIP_EXT_DIF)) { + rc = lpfc_external_dif(vport, lpfc_cmd, pnode, + &fcp_cmnd->fcpCdb[0]); + if (rc) + return rc; + } + + scan_io = (scsi_cmnd->cmnd[0] == 0 || scsi_cmnd->cmnd[0] == 0x12 || + scsi_cmnd->cmnd[0] == 0xa0); fcp_cmnd->fcpCntl1 = SIMPLE_Q; +#ifndef NO_APEX + /* + * Get the fcp priority from the table and unpack it. Each byte + * contains the priority for two luns. Low nibble has the even lun. + * Upper nibble has the odd lun. + */ + if (vport->phba->cfg_enable_fcp_priority && + (scsi_cmnd->device->lun < MAX_FCP_PRI_LUN)) { + lun_index = scsi_cmnd->device->lun >> 1; + pri = pnode->fcp_priority[lun_index]; + if (scsi_cmnd->device->lun & 1) + fcp_priority = (pri & 0xf0) >> 4; + else + fcp_priority = pri & 0xf; + } else { + fcp_priority = 0; + } + fcp_cmnd->fcpCntl1 |= (fcp_priority & 0xf) << 3; +#endif sli4 = (phba->sli_rev == LPFC_SLI_REV4); piocbq->iocb.un.fcpi.fcpi_XRdy = 0; @@ -4125,14 +4615,12 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, if (datadir == DMA_TO_DEVICE) { iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; iocb_cmd->ulpPU = PARM_READ_CHECK; - if (vport->cfg_first_burst_size && + if (pnode->first_burst && (pnode->nlp_flag & NLP_FIRSTBURST)) { + u32 xrdy_len; fcpdl = scsi_bufflen(scsi_cmnd); - if (fcpdl < vport->cfg_first_burst_size) - piocbq->iocb.un.fcpi.fcpi_XRdy = fcpdl; - else - piocbq->iocb.un.fcpi.fcpi_XRdy = - vport->cfg_first_burst_size; + xrdy_len = min(fcpdl, pnode->first_burst); + piocbq->iocb.un.fcpi.fcpi_XRdy = xrdy_len; } fcp_cmnd->fcpCntl3 = WRITE_DATA; if (hdwq) @@ -4152,9 +4640,6 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, if (hdwq) hdwq->scsi_cstat.control_requests++; } - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); /* * Finish initializing those IOCB fields that are independent * of the scsi_cmnd request_buffer @@ -4170,9 +4655,28 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); piocbq->context1 = lpfc_cmd; - piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; - piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; + if (piocbq->iocb_cmpl == NULL) + piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; + if (scan_io) { + /* + * timeout the command at the firmware level. + * The driver will not get the XRI back if + * this is a tur from the SCAN. + */ + if (scsi_cmnd->request->timeout > 0) { + tmo = (uint8_t) + (scsi_cmnd->request->timeout / 1000) + 2; + if (tmo == 0 || tmo > 60) + tmo = 30; + } else { + tmo = 30; + } + piocbq->iocb.ulpTimeout = tmo; + } else { + piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; + } piocbq->vport = vport; + return 0; } /** @@ -4275,7 +4779,7 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1418 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; @@ -4322,7 +4826,7 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, * 0, successful */ int -lpfc_check_pci_resettable(const struct lpfc_hba *phba) +lpfc_check_pci_resettable(struct lpfc_hba *phba) { const struct pci_dev *pdev = phba->pcidev; struct pci_dev *ptr = NULL; @@ -4466,10 +4970,17 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba) * This routine restarts fcp_poll timer, when FCP ring polling is enable * and FCP Ring interrupt is disable. **/ - +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_poll_timeout(unsigned long ptr) +#else void lpfc_poll_timeout(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_hba *phba = (struct lpfc_hba *) ptr; +#else struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer); +#endif if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, @@ -4480,6 +4991,672 @@ void lpfc_poll_timeout(struct timer_list *t) } } +/* + * External DIF State (EDSM) routines + * + * STATE Descriptions: + * LPFC_EDSM_INIT + * Used when LUN path is initialized and External DIF is configured for + * this HBA. This logic assumes the SCSI Layer will be sending a standard + * INQUIRY, page 0 / evpd 0, after device initialization is complete + * LPFC_EDSM_NEEDS_INQUIRY + * On a Link Up, or RSCN, previously discovered paths imay need to be checked + * for External DIF capability by issuing an INQUIRY P0 + * LPFC_EDSM_PATH_STANDBY + * Used when the LUN path points to a External DIF array; however, External + * DIF is NOT enabled at this time. + * LPFC_EDSM_PATH_READY + * Used when the LUN path points to a External DIF array and External DIF + * is enabled. + * LPFC_EDSM_PATH_CHECK + * Used when the External DIF state of the device has changed. + */ +void +lpfc_edsm_set_state(struct lpfc_vport *vport, + struct lpfc_external_dif_support *dp, + uint32_t state) +{ + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0918 EDSM: Device(%d/%lld) State Change %d to %d ", + dp->sid, dp->lun, dp->state, state); + + dp->state = state; +} + +/** + * lpfc_edsm_process_inq - Process a SCSI Layer Inquiry + * @vport: The virtual port for which this call being executed. + * @lpfc_cmd: lpfc scsi command object pointer. + * + * Piggy back on a SCSI Layer Inquiry to check for External DIF support + */ +static uint32_t +lpfc_edsm_process_inq(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + uint8_t *cdb_ptr) +{ + struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); + + /* We are only interested in EVPD=0 && page 0 */ + if ((cdb_ptr[1] & 0x1) || cdb_ptr[2]) + return 0; + /* Setup to intercept INQUIRY completion */ + piocbq->iocb_cmpl = lpfc_external_dif_cmpl; + return 1; +} + +/** + * lpfc_edsm_rw_path_rdy - Process a SCSI read/write command + * @vport: The virtual port for which this call being executed. + * @lpfc_cmd: lpfc scsi command object pointer. + * + * Process a SCSI read/write command on a External DIF path + */ +static void +lpfc_edsm_rw_path_rdy(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + uint8_t *cdb_ptr, uint32_t op) +{ + cdb_ptr[1] |= LPFC_FDIF_CDB_PROTECT; /* Set PROTECT = 001 */ + + switch (op) { + case SCSI_PROT_NORMAL: + lpfc_cmd->flags |= LPFC_SBUF_NORMAL_DIF; + break; + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + lpfc_cmd->flags |= LPFC_SBUF_PASS_DIF; + break; + } +} + +/** + * lpfc_edsm_vaiidate_target - Check a remote NPort for External DIF support + * @vport: The virtual port for which this call being executed. + * @ndlp - Pointer to lpfc_nodelist instance. + * + * Step thru all paths to a remote NPort to see if External DIF needs + * to be validated. + */ +void +lpfc_edsm_validate_target(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + struct lpfc_external_dif_support *dp; + unsigned long flags; + int rc; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0920 External DIF: Validate Target %06x: sid %d", + ndlp->nlp_DID, ndlp->nlp_sid); + + spin_lock_irqsave(&vport->external_dif_lock, flags); + list_for_each_entry(dp, &vport->external_dif_list, listentry) { + if (memcmp(&ndlp->nlp_portname, (uint8_t *)&dp->portName, + sizeof(struct lpfc_name)) == 0) { + if (dp->state != LPFC_EDSM_PATH_READY) { + rc = lpfc_issue_scsi_inquiry(vport, ndlp, + dp->lun); + if (rc == 0) { + lpfc_edsm_set_state( + vport, dp, + LPFC_EDSM_PATH_CHECK); + } else { + lpfc_edsm_set_state( + vport, dp, + LPFC_EDSM_NEEDS_INQUIRY); + } + } + } + } + spin_unlock_irqrestore(&vport->external_dif_lock, flags); +} + +/** + * lpfc_issue_scsi_inquiry - Send a driver initiated SCSI INQUIRY + * @vport: The virtual port for which this call being executed. + * @ndlp - Pointer to lpfc_nodelist instance. + * + * This function is called when the driver want to issue a SCSI + * INQUIRY Page 0 evpd 0. This is typically called when the driver + * wants to verify if a device supports External DIF. + **/ +int +lpfc_issue_scsi_inquiry(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, uint32_t lunId) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_io_buf *lpfc_cmd = NULL; + struct sli4_sge *sgl; + dma_addr_t pdma_phys_data; + IOCB_t *iocb_cmd; + uint32_t err; + + /* Check if there is a path to the target */ + if (!NLP_CHK_NODE_ACT(ndlp)) + return EINVAL; + if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) + return EINVAL; + + lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp, NULL); + if (!lpfc_cmd) + return EIO; + + /* + * lpfc_cmd is partially setup for the IO. + * We will use 4 SGEs in the SGL, immediately follwed by + * 256 bytes for the INQUIRY data. + * The lpfc_cmd data (virt) / dma_handle (phys) point to the SGL. + * The first SGE, fcp_cmnd is already setup + * The next SGE fcp_rsp is already setup. + * Next setup the SGE for the data. + */ + + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; + sgl++; + bf_set(lpfc_sli4_sge_last, sgl, 0); /* FCP_RSP is no longer last */ + sgl++; + pdma_phys_data = lpfc_cmd->dma_handle + (4 * sizeof(struct sli4_sge)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_data)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_data)); + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 1); + bf_set(lpfc_sli4_sge_offset, sgl, 0); + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(256); + sgl++; + sgl->addr_hi = 0; + sgl->addr_lo = 0; + sgl->word2 = 0; + sgl->sge_len = 0; + + /* + * The lpfc_cmd->data / lpfc_cmd->dma_handle should now point to + * the following construct: + * + * FCP_CMD SGE sizeof(sli4_sge) + * FCP_RSP SGE sizeof(sli4_sge) + * INQUIRY DATA SGE sizeof(sli4_sge) + * Zero'ed SGE sizeof(sli4_sge) + * INQUIRY Data 256 bytes + * Filler + * FCP_CMD Data sizeof(struct fcp_cmd) + * FCP_RSP_Data sizeof(struct fcp_rsp) + */ + + /* Setup the FCP_CMD */ + memset(lpfc_cmd->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); + lpfc_cmd->fcp_cmnd->fcpCdb[0] = INQUIRY; + lpfc_cmd->fcp_cmnd->fcpCdb[4] = 0xff; + lpfc_cmd->fcp_cmnd->fcpCntl3 = READ_DATA; + int_to_scsilun(lunId, &lpfc_cmd->fcp_cmnd->fcp_lun); + lpfc_cmd->fcp_cmnd->fcpDl = cpu_to_be32(0xff); + + /* Zero the FCP_RSP */ + memset((void *)lpfc_cmd->fcp_rsp, 0, sizeof(struct fcp_rsp)); + + /* + * Setup the lpfc_cmd / IOCB + * set LPFC_IO_DRVR_INIT in iocb_flag field to indicate driver use of + * iocb from scsi buf list for a driver initiated SCSI IO. + */ + lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DRVR_INIT; + lpfc_cmd->cur_iocbq.iocb_cmpl = lpfc_external_dif_cmpl; + lpfc_cmd->cur_iocbq.context1 = lpfc_cmd; + lpfc_cmd->cur_iocbq.context2 = (void *)(unsigned long)lunId; + lpfc_cmd->cur_iocbq.vport = vport; + lpfc_cmd->timeout = 30; + lpfc_cmd->pCmd = NULL; + lpfc_cmd->seg_cnt = 1; + lpfc_cmd->rdata = (void *)ndlp; /* Save ndlp in rdata */ + lpfc_cmd->ndlp = ndlp; + + iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; + iocb_cmd->ulpPU = PARM_READ_CHECK; + iocb_cmd->un.fcpi.fcpi_parm = 0xff; + iocb_cmd->ulpContext = ndlp->nlp_rpi; + iocb_cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) + iocb_cmd->ulpFCP2Rcvy = 1; + iocb_cmd->ulpClass = (ndlp->nlp_fcp_info & 0x0f); + iocb_cmd->ulpTimeout = lpfc_cmd->timeout; + + err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, + &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0919 External DIF: Issue INQUIRY (%d/%d) ret %d " + "flag x%x iotag x%x xri x%x", + ndlp->nlp_sid, lunId, err, + lpfc_cmd->cur_iocbq.iocb_flag, + lpfc_cmd->cur_iocbq.iotag, + lpfc_cmd->cur_iocbq.sli4_xritag); + + if (err) { + lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_IO_DRVR_INIT; + lpfc_cmd->rdata = NULL; + lpfc_release_scsi_buf(phba, lpfc_cmd); + return EIO; + } + + if (phba->cfg_xri_rebalancing) + lpfc_keep_pvt_pool_above_lowwm(phba, lpfc_cmd->hdwq_no); + + return 0; +} + +/** + * lpfc_external_dif_match - Look up a specific External DIF device + * @vport: The virtual port for which this call is being executed. + * @lun: lun id used to specify the desired External DIF device + * @sid: SCSI id used to specify the desired External DIF device + * + * This routine scans the discovered External DIF devices for the vport + * for a match using the lun/sid criteria. + * MUST hold external_dif_lock BEFORE calling this routine + * + * Return code : + * NULL - device not found + * dp - struct lpfc_external_dif_support of matching device + **/ +static struct lpfc_external_dif_support * +lpfc_external_dif_match(struct lpfc_vport *vport, uint64_t lun, uint32_t sid) +{ + struct lpfc_external_dif_support *dp; + + list_for_each_entry(dp, &vport->external_dif_list, listentry) { + if ((dp->sid == sid) && (dp->lun == lun)) { + return dp; + } + } + return NULL; +} + +/** + * lpfc_retry_scsi_inquiry - Send a driver initiated SCSI INQUIRY + * @vport: The virtual port for which this call being executed. + * @ndlp - Pointer to lpfc_nodelist instance. + * + * This function is called when the driver want to retry a SCSI + * INQUIRY Page 0 evpd 0. This is typically called when the driver + * wants to verify if a device supports External DIF and a previous + * driver initiated INQUIRY has failed. + **/ +int +lpfc_retry_scsi_inquiry(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint32_t lunId, uint32_t status) +{ + struct lpfc_external_dif_support *dp; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&vport->external_dif_lock, flags); + dp = lpfc_external_dif_match(vport, lunId, ndlp->nlp_sid); + if (dp) { + dp->inq_retry++; + if (dp->inq_retry < LPFC_EDSM_MAX_RETRY) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0921 External DIF: Inquiry retry %d " + "NPort %06x: (%d/%d) err x%x", + dp->inq_retry, ndlp->nlp_DID, + ndlp->nlp_sid, lunId, status); + rc = lpfc_issue_scsi_inquiry(vport, ndlp, dp->lun); + } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0922 External DIF: Inquiry retry " + "exceeded NPort %06x: (%d/%d) err x%x", + ndlp->nlp_DID, ndlp->nlp_sid, + lunId, status); + rc = ENXIO; + } + } + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + return rc; +} + +/** + * lpfc_external_dif_cmpl - IOCB completion routine for a External DIF IO + * @phba: The Hba for which this call is being executed. + * @pIocbIn: The command IOCBQ for the scsi cmnd. + * @pIocbOut: The response IOCBQ for the scsi cmnd. + * + * This routine processes the External DIF SCSi command cmpl before calling the + * normal SCSI cmpl routine (lpfc_scsi_cmd_iocb_cmpl). There are 2 types of + * External DIF completions, INQUIRY and READ/WRITE SCSI commands. + * + * We use INQUIRY to discover External DIF devices. An External DIF device does + * not advertise itself as T10-DIF capable using standard bits in the INQUIRY + * and READ_CAPACITY commands. Instead, it uses some vendor specfic information + * in the standard INQUIRY command to turn on this feature. + * + * For READ/WRITE IOs we convert the IO back into a normal IO so it can be + * completed to the SCSI layer. The SCSI layer is unaware the IO was actually + * transmitted on the wire in T10 DIF Type 1 format. + **/ +static void +lpfc_external_dif_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + struct lpfc_iocbq *pIocbOut) +{ + struct lpfc_io_buf *lpfc_cmd = + (struct lpfc_io_buf *)pIocbIn->context1; + struct lpfc_vport *vport = pIocbIn->vport; + struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; + struct lpfc_external_dif_support *dp; + uint32_t resp_info = fcprsp->rspStatus2; + struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; + uint32_t status = pIocbOut->iocb.ulpStatus; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_vendor_dif *vendor_dif_infop; + struct fcp_cmnd *fcpcmd; + struct scatterlist *sgde; + unsigned long flags; + uint8_t *data_inq, *buf = NULL, *ptr; + uint8_t *name; + uint32_t cnt, cmd, lun, resid, len; + + if (status && cmnd) { + if ((status != IOSTAT_FCP_RSP_ERROR) || + !(resp_info & RESID_UNDER)) + goto out; + } + fcpcmd = lpfc_cmd->fcp_cmnd; + cmd = fcpcmd->fcpCdb[0]; + + /* Only success and RESID_UNDER make it here */ + switch (cmd) { + case INQUIRY: + + if (cmnd) { + /* Inquiry issued by SCSI Layer */ + rdata = lpfc_cmd->rdata; + ndlp = rdata->pnode; + + sgde = scsi_sglist(cmnd); + buf = kmalloc(scsi_bufflen(cmnd), GFP_ATOMIC); + len = scsi_bufflen(cmnd); + ptr = buf; + while (sgde && len) { +#if (KERNEL_MAJOR < 3) || ((KERNEL_MAJOR == 3) && (KERNEL_MINOR < 4)) + data_inq = kmap_atomic(sg_page(sgde), KM_IRQ0) + + sgde->offset; +#else + data_inq = kmap_atomic(sg_page(sgde)) + + sgde->offset; +#endif + memcpy(ptr, data_inq, sgde->length); + len -= sgde->length; + ptr += sgde->length; +#if (KERNEL_MAJOR < 3) || ((KERNEL_MAJOR == 3) && (KERNEL_MINOR < 4)) + kunmap_atomic(data_inq - sgde->offset, KM_IRQ0); +#else + kunmap_atomic(data_inq - sgde->offset); +#endif + sgde = sg_next(sgde); + } + + data_inq = buf; + lun = cmnd->device->lun; + } else { + /* Inquiry issued by driver */ + ndlp = (void *)lpfc_cmd->rdata; + lpfc_cmd->rdata = NULL; + + data_inq = (uint8_t *)lpfc_cmd->dma_sgl + + (4 * sizeof(struct sli4_sge)); + lun = (uint32_t)(unsigned long)(pIocbIn->context2); + + if ((status != IOSTAT_FCP_RSP_ERROR) || + !(resp_info & RESID_UNDER)) { + /* If its an unexpected error, retry it */ + lpfc_retry_scsi_inquiry(vport, ndlp, lun, + status); + break; + } + } + + /* Jump to T10 Vendor Identification field */ + data_inq += LPFC_INQ_VID_OFFSET; + if ((memcmp(data_inq, LPFC_INQ_FDIF_VENDOR, + sizeof(LPFC_INQ_FDIF_VENDOR) != 0))) { + ndlp->nlp_flag &= ~NLP_EXTERNAL_DIF; + ndlp->nlp_flag |= NLP_SKIP_EXT_DIF; + break; + } + + /* Jump to Vendor specific DIF info */ + vendor_dif_infop = (struct lpfc_vendor_dif *)(data_inq + + (LPFC_INQ_VDIF_OFFSET - LPFC_INQ_VID_OFFSET)); + + name = (uint8_t *)&ndlp->nlp_portname; + + spin_lock_irqsave(&vport->external_dif_lock, flags); + dp = lpfc_external_dif_match(vport, lun, ndlp->nlp_sid); + if (dp) { + dp->inq_cnt++; + dp->inq_retry = 0; + ndlp->nlp_flag |= NLP_EXTERNAL_DIF; + + if (dp->state == LPFC_EDSM_PATH_READY) { + spin_unlock_irqrestore( + &vport->external_dif_lock, flags); + break; /* device already exists */ + } + } else { + + /* New External DIF device found */ + dp = kmalloc(sizeof(struct lpfc_external_dif_support), + GFP_ATOMIC); + if (!dp) { + spin_unlock_irqrestore( + &vport->external_dif_lock, flags); + break; + } + memset(dp, 0x0, + sizeof(struct lpfc_external_dif_support)); + dp->lun = lun; + dp->sid = ndlp->nlp_sid; + dp->dif_info = vendor_dif_infop->dif_info; + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_INIT); + memcpy(&dp->portName, name, sizeof(struct lpfc_name)); + dp->inq_cnt = 1; + dp->err3f_cnt = 0; + dp->err4b_cnt = 0; + ndlp->nlp_flag |= NLP_EXTERNAL_DIF; + + list_add_tail(&dp->listentry, + &vport->external_dif_list); + } + + /* Make sure the INQUIRY payload has our + * vendor specfic info included. + */ + if (status == IOSTAT_FCP_RSP_ERROR) + resid = be32_to_cpu(fcprsp->rspResId); + else + resid = 0; + cnt = be32_to_cpu(fcpcmd->fcpDl) - resid; + if (cnt < LPFC_INQ_FDIF_SZ) { + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_IGNORE); + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0917 External DIF Vendor size error " + "Data: %02x %02x %02x\n", + be32_to_cpu(fcpcmd->fcpDl), + be32_to_cpu(fcprsp->rspResId), + vendor_dif_infop->length); + ndlp->nlp_flag &= ~NLP_EXTERNAL_DIF; + break; + } + + /* Check to see if External DIF protection is enabled and we + * are version 1. + */ + if ((vendor_dif_infop->length != LPFC_INQ_FDIF_SIZE) || + (vendor_dif_infop->version != LPFC_INQ_FDIF_VERSION)) { + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_IGNORE); + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + lpfc_printf_vlog(vport, KERN_ERR, LOG_EDIF, + "0709 Possible External DIF INQUIRY " + "info error: " + "lun %d xri x%x fcpdl %d resid %d " + "Data: %02x %02x %02x\n", + lun, lpfc_cmd->cur_iocbq.sli4_xritag, + be32_to_cpu(fcpcmd->fcpDl), resid, + vendor_dif_infop->length, + vendor_dif_infop->version, + vendor_dif_infop->dif_info); + dp->dif_info = 0; + ndlp->nlp_flag &= ~NLP_EXTERNAL_DIF; + break; + } + + dp->dif_info = vendor_dif_infop->dif_info; + + /* Currently we only support DIF Type 1 * (GRD_CHK / REF_CHK) */ + if (vendor_dif_infop->dif_info != (LPFC_FDIF_PROTECT | + LPFC_FDIF_REFCHK | LPFC_FDIF_GRDCHK)) { + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_PATH_STANDBY); + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0701 External DIF INQUIRY protection " + "off: xri x%x fcpdl %d resid %d " + "Data: %02x %02x %02x\n", + lpfc_cmd->cur_iocbq.sli4_xritag, + be32_to_cpu(fcpcmd->fcpDl), + be32_to_cpu(fcprsp->rspResId), + vendor_dif_infop->length, + vendor_dif_infop->version, + vendor_dif_infop->dif_info); + break; + } + + lpfc_edsm_set_state(vport, dp, LPFC_EDSM_PATH_READY); + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + + lpfc_printf_vlog(vport, KERN_WARNING, LOG_EDIF, + "0712 Discovered External DIF device NPortId " + "x%x: scsi_id x%x: lun_id x%llx: WWPN " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + ndlp->nlp_DID, dp->sid, dp->lun, + *name, *(name+1), *(name+2), *(name+3), + *(name+4), *(name+5), *(name+6), *(name+7)); + break; + default: + break; + } +out: + kfree(buf); + if (lpfc_cmd->cur_iocbq.iocb_flag & LPFC_IO_DRVR_INIT) { + if (ndlp == NULL) { + ndlp = (void *)lpfc_cmd->rdata; + lpfc_cmd->rdata = NULL; + } + pIocbIn->context2 = NULL; + lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_IO_DRVR_INIT; + lpfc_release_scsi_buf(phba, lpfc_cmd); + return; + } + + lpfc_scsi_cmd_iocb_cmpl(phba, pIocbIn, pIocbOut); +} + +/** + * lpfc_external_dif - Check to see if we want to process this IO as a External DIF + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: Pointer to lpfc_io_buf data structure. + * + * This routine will selectively force normal IOs to be processed as a + * READ_STRIP / WRITE_INSERT T10-DIF IO. The upper SCSI Layer will be unaware + * that the IO is going to be transmitted on the wire with T10-DIF protection + * data. This routine also diverts INQUIRY command cmpletions so they can be + * used to scan for External DIF devices. + **/ +static int +lpfc_external_dif(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + struct lpfc_nodelist *ndlp, uint8_t *cdb_ptr) +{ + struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; + uint32_t op = scsi_get_prot_op(cmnd); + struct lpfc_external_dif_support *dp; + struct scsi_device *sdev; + unsigned long flags; + int rc; + + switch (op) { + case SCSI_PROT_NORMAL: + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + break; + default: + return 0; + } + + switch (cdb_ptr[0]) { + case INQUIRY: + lpfc_edsm_process_inq(vport, lpfc_cmd, cdb_ptr); + break; + case READ_10: + case READ_12: + case READ_16: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case WRITE_SAME: + case WRITE_SAME_16: + case WRITE_VERIFY: + case VERIFY: + case VERIFY_12: + case VERIFY_16: + + /* Is this an External DIF device */ + sdev = cmnd->device; + spin_lock_irqsave(&vport->external_dif_lock, flags); + dp = lpfc_external_dif_match(vport, sdev->lun, sdev->id); + if (dp == NULL) { + spin_unlock_irqrestore(&vport->external_dif_lock, + flags); + break; + } + switch (dp->state) { + case LPFC_EDSM_PATH_STANDBY: + /* IO is sent normally */ + break; + + case LPFC_EDSM_NEEDS_INQUIRY: + rc = lpfc_issue_scsi_inquiry(vport, ndlp, dp->lun); + if (rc == 0) + lpfc_edsm_set_state(vport, dp, + LPFC_EDSM_PATH_CHECK); + else + lpfc_edsm_set_state(vport, dp, + LPFC_EDSM_NEEDS_INQUIRY); + /* fall through */ + + case LPFC_EDSM_PATH_CHECK: + /* In process of checking path, need to retry the IO */ + spin_unlock_irqrestore(&vport->external_dif_lock, + flags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_EDIF, + "0923 External DIF: In process of " + "checking path, retry IO\n"); + return 1; + + case LPFC_EDSM_PATH_READY: + /* modify CDB as needed */ + lpfc_edsm_rw_path_rdy(vport, lpfc_cmd, cdb_ptr, op); + lpfc_cmd->edifp = (void *)dp; + + default: + break; + } + spin_unlock_irqrestore(&vport->external_dif_lock, flags); + break; + default: + break; + } + return 0; +} + /** * lpfc_queuecommand - scsi_host_template queuecommand entry point * @cmnd: Pointer to scsi_cmnd data structure. @@ -4494,8 +5671,15 @@ void lpfc_poll_timeout(struct timer_list *t) * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ static int +#ifdef DEF_SCSI_QCMD lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +#else +lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) +#endif { +#ifndef DEF_SCSI_QCMD + struct Scsi_Host *shost = cmnd->device->host; +#endif struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata; @@ -4503,27 +5687,43 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) struct lpfc_io_buf *lpfc_cmd; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); int err, idx; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - int cpu; -#endif + uint64_t start; + start = ktime_get_ns(); rdata = lpfc_rport_data_from_scsi_device(cmnd->device); /* sanity check on references */ if (unlikely(!rdata) || unlikely(!rport)) goto out_fail_command; +#ifndef DEF_SCSI_QCMD + spin_unlock_irq(shost->host_lock); +#endif + err = fc_remote_port_chkready(rport); if (err) { cmnd->result = err; goto out_fail_command; } + /* + * Do not let the mid-layer retry I/O too fast. If an I/O is retried + * without waiting a bit then indicate that the device is busy. + */ + if (cmnd->retries && + time_before(jiffies, (cmnd->jiffies_at_alloc + + msecs_to_jiffies(LPFC_RETRY_PAUSE * + cmnd->retries)))) { +#ifndef DEF_SCSI_QCMD + spin_lock_irq(shost->host_lock); +#endif + return SCSI_MLQUEUE_DEVICE_BUSY; + } ndlp = rdata->pnode; if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED))) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9058 BLKGRD: ERROR: rcvd protected cmd:%02x" " op:%02x str=%s without registering for" " BlockGuard - Rejecting command\n", @@ -4537,35 +5737,47 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) * transport is still transitioning. */ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - goto out_tgt_busy; + goto out_tgt_busy1; + + /* Check if IO qualifies for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + cmnd->sc_data_direction == DMA_FROM_DEVICE && + (scsi_sg_count(cmnd))) { + /* Latency start time saved in rx_cmd_start later in routine */ + err = lpfc_update_cmf_cmd(phba, scsi_bufflen(cmnd)); + if (err) + goto out_tgt_busy1; + } + if (lpfc_ndlp_check_qdepth(phba, ndlp)) { if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR, - "3377 Target Queue Full, scsi Id:%d " - "Qdepth:%d Pending command:%d" - " WWNN:%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x, " - " WWPN:%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x", - ndlp->nlp_sid, ndlp->cmd_qdepth, - atomic_read(&ndlp->cmd_pending), - ndlp->nlp_nodename.u.wwn[0], - ndlp->nlp_nodename.u.wwn[1], - ndlp->nlp_nodename.u.wwn[2], - ndlp->nlp_nodename.u.wwn[3], - ndlp->nlp_nodename.u.wwn[4], - ndlp->nlp_nodename.u.wwn[5], - ndlp->nlp_nodename.u.wwn[6], - ndlp->nlp_nodename.u.wwn[7], - ndlp->nlp_portname.u.wwn[0], - ndlp->nlp_portname.u.wwn[1], - ndlp->nlp_portname.u.wwn[2], - ndlp->nlp_portname.u.wwn[3], - ndlp->nlp_portname.u.wwn[4], - ndlp->nlp_portname.u.wwn[5], - ndlp->nlp_portname.u.wwn[6], - ndlp->nlp_portname.u.wwn[7]); - goto out_tgt_busy; + lpfc_throttle_vlog(ndlp->vport, &ndlp->log, + LOG_FCP_ERROR, + "3377 Target Queue Full, scsi Id:%d" + " Qdepth:%d Pending command:%d" + " WWNN:%02x:%02x:%02x:%02x:" + "%02x:%02x:%02x:%02x, " + " WWPN:%02x:%02x:%02x:%02x" + ":%02x:%02x:%02x:%02x", + ndlp->nlp_sid, ndlp->cmd_qdepth, + atomic_read(&ndlp->cmd_pending), + ndlp->nlp_nodename.u.wwn[0], + ndlp->nlp_nodename.u.wwn[1], + ndlp->nlp_nodename.u.wwn[2], + ndlp->nlp_nodename.u.wwn[3], + ndlp->nlp_nodename.u.wwn[4], + ndlp->nlp_nodename.u.wwn[5], + ndlp->nlp_nodename.u.wwn[6], + ndlp->nlp_nodename.u.wwn[7], + ndlp->nlp_portname.u.wwn[0], + ndlp->nlp_portname.u.wwn[1], + ndlp->nlp_portname.u.wwn[2], + ndlp->nlp_portname.u.wwn[3], + ndlp->nlp_portname.u.wwn[4], + ndlp->nlp_portname.u.wwn[5], + ndlp->nlp_portname.u.wwn[6], + ndlp->nlp_portname.u.wwn[7]); + goto out_tgt_busy2; } } @@ -4578,6 +5790,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) "IO busied\n"); goto out_host_busy; } + lpfc_cmd->rx_cmd_start = start; /* * Store the midlayer's command structure for the completion phase @@ -4586,10 +5799,18 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) lpfc_cmd->pCmd = cmnd; lpfc_cmd->rdata = rdata; lpfc_cmd->ndlp = ndlp; + lpfc_cmd->cur_iocbq.iocb_cmpl = NULL; cmnd->host_scribble = (unsigned char *)lpfc_cmd; +#ifndef DEF_SCSI_QCMD + cmnd->scsi_done = done; +#endif - if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { - if (vport->phba->cfg_enable_bg) { + err = lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); + if (err) + goto out_host_busy_release_buf; + + if (lpfc_scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { lpfc_printf_vlog(vport, KERN_INFO, LOG_SCSI_CMD, "9033 BLKGRD: rcvd %s cmd:x%x " @@ -4602,7 +5823,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) } err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); } else { - if (vport->phba->cfg_enable_bg) { + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { lpfc_printf_vlog(vport, KERN_INFO, LOG_SCSI_CMD, "9038 BLKGRD: rcvd PROT_NORMAL cmd: " @@ -4615,34 +5836,21 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } - if (err == 2) { - cmnd->result = DID_ERROR << 16; - goto out_fail_command_release_buf; - } else if (err) { + if (unlikely(err)) { + if (err == 2) { + cmnd->result = ScsiResult(DID_ERROR, 0); + goto out_fail_command_release_buf; + } goto out_host_busy_free_buf; } - lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { - cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - struct lpfc_sli4_hdw_queue *hdwq = - &phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no]; - hdwq->cpucheck_xmt_io[cpu]++; - } - } -#endif - err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); - if (err) { + if (cmnd->cmnd[0] == 0 || cmnd->cmnd[0] == 0x12 || + cmnd->cmnd[0] == 0xa0 || cmnd->cmnd[0] == 0x11) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "3376 FCP could not issue IOCB err %x" - "FCP cmd x%x <%d/%llu> " + "3322 FCP cmd x%x <%d/%lld> " "sid: x%x did: x%x oxid: x%x " - "Data: x%x x%x x%x x%x\n", - err, cmnd->cmnd[0], + "Data: x%x x%x x%x x%x %x\n", + cmnd->cmnd[0], cmnd->device ? cmnd->device->id : 0xffff, cmnd->device ? cmnd->device->lun : (u64) -1, vport->fc_myDID, ndlp->nlp_DID, @@ -4652,10 +5860,46 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) lpfc_cmd->cur_iocbq.iocb.ulpIoTag, lpfc_cmd->cur_iocbq.iocb.ulpTimeout, (uint32_t) - (cmnd->request->timeout / 1000)); + (cmnd->request->timeout / 1000), + lpfc_cmd->cur_iocbq.iocb.ulpCommand); + } + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); +#endif + err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, + &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (phba->ktime_on) { + lpfc_cmd->ts_cmd_start = start; + lpfc_cmd->ts_last_cmd = phba->ktime_last_cmd; + lpfc_cmd->ts_cmd_wqput = ktime_get_ns(); + } else { + lpfc_cmd->ts_cmd_start = 0; + } +#endif + if (err) { + lpfc_throttle_vlog(vport, &vport->log, LOG_FCP, + "3376 FCP could not issue IOCB err %x" + "FCP cmd x%x <%d/%llu> " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x x%x\n", + err, cmnd->cmnd[0], + cmnd->device ? cmnd->device->id : 0xffff, + cmnd->device ? cmnd->device->lun : (u64) -1, + vport->fc_myDID, ndlp->nlp_DID, + phba->sli_rev == LPFC_SLI_REV4 ? + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, + lpfc_cmd->cur_iocbq.iocb.ulpContext, + lpfc_cmd->cur_iocbq.iocb.ulpIoTag, + lpfc_cmd->cur_iocbq.iocb.ulpTimeout, + (uint32_t) + (cmnd->request->timeout / 1000)); goto out_host_busy_free_buf; } + if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); @@ -4667,6 +5911,9 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) if (phba->cfg_xri_rebalancing) lpfc_keep_pvt_pool_above_lowwm(phba, lpfc_cmd->hdwq_no); +#ifndef DEF_SCSI_QCMD + spin_lock_irq(shost->host_lock); +#endif return 0; out_host_busy_free_buf: @@ -4684,21 +5931,320 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) phba->sli4_hba.hdwq[idx].scsi_cstat.control_requests--; } } + out_host_busy_release_buf: lpfc_release_scsi_buf(phba, lpfc_cmd); out_host_busy: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); +#ifndef DEF_SCSI_QCMD + spin_lock_irq(shost->host_lock); +#endif return SCSI_MLQUEUE_HOST_BUSY; - out_tgt_busy: + out_tgt_busy2: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); + out_tgt_busy1: +#ifndef DEF_SCSI_QCMD + spin_lock_irq(shost->host_lock); +#endif return SCSI_MLQUEUE_TARGET_BUSY; out_fail_command_release_buf: lpfc_release_scsi_buf(phba, lpfc_cmd); + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); out_fail_command: +#ifdef DEF_SCSI_QCMD cmnd->scsi_done(cmnd); +#else + spin_lock_irq(shost->host_lock); + done(cmnd); +#endif return 0; } +/* lpfc_mode_sense_cmpl. + * + * This is the completion routine for a driver-issued mode sense + * used to determine if an FCP target supports first_burst. This + * routine could be used for other mode sense data values. + */ +void +lpfc_mode_sense_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *p_io_in, + struct lpfc_iocbq *p_io_out) +{ + struct lpfc_io_buf *lpfc_cmd = p_io_in->context1; + u32 resp_info = lpfc_cmd->fcp_rsp->rspStatus2; + struct sli4_sge *sgl; + struct lpfc_nodelist *ndlp = lpfc_cmd->ndlp; + u32 status = p_io_out->iocb.ulpStatus; + u32 result = p_io_out->iocb.un.ulpWord[4] & IOERR_PARAM_MASK; + u32 fb = 0; + int ret_val; + struct lpfc_first_burst_page *p_data; + + /* Make sure the driver's remoteport state is still valid. If the + * reference put results in an invalid remoteport, just exit. + */ + ret_val = lpfc_nlp_put(ndlp); + if (ret_val) { + ret_val = -ENOMEM; + goto out; + } + + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + ndlp->nlp_state != NLP_STE_MAPPED_NODE) { + ret_val = -ENXIO; + goto out; + } + + /* Only accept a successful IO or an IO with an underflow status + * because any other FCP RSP error indicates the IO had some other + * error. + */ + if (status && + !(status == IOSTAT_FCP_RSP_ERROR && resp_info & RESID_UNDER)) { + ret_val = -EIO; + goto out; + } + + /* No errors. clear the return value. */ + ret_val = 0; + + /* Skip over the SGEs and headers to get the response data region. */ + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; + sgl += 4; + p_data = (struct lpfc_first_burst_page *)(((u32 *)sgl) + 3); + + /* Validate the correct page code response and the number of bytes + * available before reading the first burst size. Initialize + * the first_burst in case the response doesn't have a value. + */ + ndlp->first_burst = 0; + if (p_data->page_code == 0x2 && p_data->page_len == 0xe) { + fb = be16_to_cpu(p_data->first_burst); + ndlp->first_burst = min((u32)(fb * 512), (u32)LPFC_FCP_FB_MAX); + } else { + lpfc_printf_vlog(phba->pport, KERN_INFO, + LOG_FCP | LOG_FCP_ERROR, + "6332 Clear first burst value " + "Code x%x Len x%x\n", p_data->page_code, + p_data->page_len); + } + + lpfc_printf_vlog(phba->pport, KERN_INFO, + LOG_FCP | LOG_FCP_ERROR, + "6336 FB Rsp: DID x%x Data: x%x x%x x%x x%x x%x x%x " + "x%x\n", ndlp->nlp_DID, fb, ndlp->first_burst, + status, result, resp_info, + lpfc_cmd->cur_iocbq.iocb_flag, ret_val); + + /* Pick up SLI4 exhange busy status from HBA */ + if (p_io_out->iocb_flag & LPFC_EXCHANGE_BUSY) + lpfc_cmd->flags |= LPFC_SBUF_XBUSY; + else + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; + + out: + /* Push a driver message only if the IO completion is in error. */ + if (ret_val) + lpfc_printf_vlog(phba->pport, KERN_INFO, + LOG_FCP_UNDER | LOG_FCP_ERROR, + "6331 FB err %d resp_info x%x\n", + ret_val, status, result, resp_info); + + p_io_in->context2 = NULL; + lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_IO_DRVR_INIT; + lpfc_release_scsi_buf(phba, lpfc_cmd); +} + +/** + * lpfc_init_scsi_cmd - Initiatize SCSI command-specific fields. + * @vport: The virtual port for which this call being executed. + * @lpfc_cmd: The lpfc_io_buf containing this command. + * @dev_id - device identifier for this command + * @cmd_id: SCSI command used to format the driver io and CDB + * @data_len: Number of bytes available for data. + * + * This routine initializes an lpfc_io_buf for the specified @cmd_id to + * the specified @dev_id for @data_len bytes. + * + * Returns: + * 0 - on success + * A negative error value in the form -Exxxx otherwise. + * + **/ +static int +lpfc_init_scsi_cmd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, + struct lpfc_scsi_io_req *cmd_req, u32 data_len) +{ + int ret = 0; + IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + + /* Set command-independent values. */ + lpfc_cmd->fcp_cmnd->fcpCdb[0] = cmd_req->cmd_id; + lpfc_cmd->fcp_cmnd->fcpCdb[4] = data_len; + lpfc_cmd->cur_iocbq.iocb_cmpl = cmd_req->cmd_cmpl; + lpfc_cmd->fcp_cmnd->fcpDl = cpu_to_be32(data_len); + int_to_scsilun(cmd_req->dev_id, &lpfc_cmd->fcp_cmnd->fcp_lun); + + /* SCSI Command specific initialization. */ + switch (cmd_req->cmd_id) { + case MODE_SENSE: + /* Send the DISCONNECT-RECONNECT page code */ + lpfc_cmd->fcp_cmnd->fcpCdb[2] = 0x2; + lpfc_cmd->fcp_cmnd->fcpCntl3 = READ_DATA; + lpfc_cmd->cur_iocbq.context2 = NULL; + iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; + iocb_cmd->ulpPU = PARM_READ_CHECK; + break; + default: + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6335 Unsupported CMD x%x\n", cmd_req->cmd_id); + ret = -EINVAL; + break; + } + return ret; +} + +/** + * lpfc_issue_scsi_cmd - Send a driver initiated SCSI cmd + * @vport: The virtual port for which this call being executed. + * @ndlp - Pointer to lpfc_nodelist instance. + * @scsi_io_req - pointer to a job structure with the command, device ids, + * and the associated completion routine. + * + * The driver calls this function to dynamically determine if an FCP + * target suppports a particular feature. The caller needs to specify + * what command is needed to what device. + * + * Returns: + * 0 - on success + * A negative error value in the form -Exxxx otherwise. + * + **/ +int +lpfc_issue_scsi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct lpfc_scsi_io_req *cmd_req) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_io_buf *lpfc_cmd = NULL; + struct sli4_sge *sgl; + dma_addr_t pdma_phys_data; + IOCB_t *iocb_cmd; + int err = 0; + + /* Requirements must be met. */ + if (phba->sli_rev != LPFC_SLI_REV4 || + phba->hba_flag == HBA_FCOE_MODE || + !phba->pport->cfg_first_burst_size) + return -EPERM; + + /* Because the driver potentially sends an FCP and NVME PRLI, the + * caller is required to ensure an FCP PRLI has been successfully + * completed. + */ + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return -EINVAL; + + lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp, NULL); + if (!lpfc_cmd) + return -EIO; + + /* + * Every lpfc_io_buf is partially setup for the IO - an FCP Cmd SGE + * and an FCP RSP SGE. This routine configures two more - one for + * this scsi command and an empty SGE. A 256 byte data area follows + * for the command payload data. + */ + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; + sgl++; + bf_set(lpfc_sli4_sge_last, sgl, 0); + sgl++; + + /* SGE for the SCSI command */ + pdma_phys_data = lpfc_cmd->dma_handle + (4 * sizeof(struct sli4_sge)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_data)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_data)); + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 1); + bf_set(lpfc_sli4_sge_offset, sgl, 0); + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(LPFC_DATA_SIZE); + sgl++; + + /* Empty SGE. Clear to prevent stale data errors. */ + sgl->addr_hi = 0; + sgl->addr_lo = 0; + sgl->word2 = 0; + sgl->sge_len = 0; + + /* Finish prepping the command, response and scsi command. */ + memset(lpfc_cmd->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); + memset((void *)lpfc_cmd->fcp_rsp, 0, sizeof(struct fcp_rsp)); + err = lpfc_init_scsi_cmd(vport, lpfc_cmd, cmd_req, LPFC_DATA_SIZE); + if (err) { + err = -EPERM; + goto out_err; + } + + /* This is an FCP IO the driver tracks so don't let it stay + * outstanding forever - provide a generous 16 sec TMO. + */ + lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + lpfc_cmd->cur_iocbq.context1 = lpfc_cmd; + lpfc_cmd->cur_iocbq.vport = vport; + lpfc_cmd->timeout = LPFC_DRVR_TIMEOUT; + lpfc_cmd->pCmd = NULL; + lpfc_cmd->seg_cnt = 1; + + /* Get an ndlp reference. Ignore rdata as this IO is driver owned. */ + lpfc_cmd->ndlp = lpfc_nlp_get(ndlp); + if (!lpfc_cmd->ndlp) { + err = -EINVAL; + goto out_err; + } + + iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + iocb_cmd->un.fcpi.fcpi_parm = LPFC_DATA_SIZE; + iocb_cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) + iocb_cmd->ulpFCP2Rcvy = 1; + iocb_cmd->ulpClass = (ndlp->nlp_fcp_info & 0x0f); + iocb_cmd->ulpTimeout = lpfc_cmd->timeout; + + err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, &lpfc_cmd->cur_iocbq, + SLI_IOCB_RET_IOCB); + if (err) { + err = -EIO; + lpfc_nlp_put(ndlp); + goto out_err; + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP | LOG_FCP_ERROR, + "6333 Issue cmd x%x to 0x%06x status %d " + "flag x%x iotag x%x xri x%x\n", + cmd_req->cmd_id, ndlp->nlp_DID, err, + lpfc_cmd->cur_iocbq.iocb_flag, + lpfc_cmd->cur_iocbq.iotag, + lpfc_cmd->cur_iocbq.sli4_xritag); + + if (phba->cfg_xri_rebalancing) + lpfc_keep_pvt_pool_above_lowwm(phba, lpfc_cmd->hdwq_no); + return 0; + + out_err: + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP | LOG_FCP_ERROR, + "6337 Could not issue cmd x%x err %d\n", + cmd_req->cmd_id, err); + lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_IO_DRVR_INIT; + lpfc_cmd->rdata = NULL; + lpfc_release_scsi_buf(phba, lpfc_cmd); + return err; +} /** * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point @@ -4849,6 +6395,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb, 0); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (ret_val == IOCB_ERROR) { /* Indicate the IO is not being aborted by the driver. */ iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; @@ -4869,7 +6418,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); wait_for_cmpl: - /* Wait for abort to complete */ + /* + * iocb_flag is set to LPFC_DRIVER_ABORTED before we wait + * for abort to complete. + */ wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); @@ -4878,7 +6430,7 @@ wait_for_cmpl: if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0748 abort handler timed out waiting " "for aborting I/O (xri:x%x) to complete: " "ret %#x, ID %d, LUN %llu\n", @@ -4960,8 +6512,8 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) rsp_info_code = fcprsp->rspInfo3; - lpfc_printf_vlog(vport, KERN_INFO, - LOG_FCP, + lpfc_optioned_vlog(vport, &vport->log, + KERN_INFO, LOG_FCP, "0706 fcp_rsp valid 0x%x," " rsp len=%d code 0x%x\n", rsp_info, @@ -4975,8 +6527,10 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) ((rsp_len == 8) || (rsp_len == 4))) { switch (rsp_info_code) { case RSP_NO_FAILURE: - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0715 Task Mgmt No Failure\n"); + lpfc_optioned_vlog(vport, &vport->log, + KERN_INFO, LOG_FCP, + "0715 Task Mgmt No " + "Failure\n"); ret = SUCCESS; break; case RSP_TM_NOT_SUPPORTED: /* TM rejected */ @@ -5018,7 +6572,7 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) **/ static int lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, - unsigned int tgt_id, uint64_t lun_id, + unsigned tgt_id, uint64_t lun_id, uint8_t task_mgmt_cmd) { struct lpfc_hba *phba = vport->phba; @@ -5031,11 +6585,11 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, int status; rdata = lpfc_rport_data_from_scsi_device(cmnd->device); - if (!rdata || !rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) - return FAILED; pnode = rdata->pnode; + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + return FAILED; - lpfc_cmd = lpfc_get_scsi_buf(phba, pnode, NULL); + lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode, NULL); if (lpfc_cmd == NULL) return FAILED; lpfc_cmd->timeout = phba->cfg_task_mgmt_tmo; @@ -5070,8 +6624,8 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, if ((status != IOCB_SUCCESS) || (iocbqrsp->iocb.ulpStatus != IOSTAT_SUCCESS)) { if (status != IOCB_SUCCESS || - iocbqrsp->iocb.ulpStatus != IOSTAT_FCP_RSP_ERROR) - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + iocbqrsp->iocb.ulpStatus != IOSTAT_FCP_RSP_ERROR) + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0727 TMF %s to TGT %d LUN %llu " "failed (%d, %d) iocb_flag x%x\n", lpfc_taskmgmt_name(task_mgmt_cmd), @@ -5087,7 +6641,8 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, ret = lpfc_check_fcp_rsp(vport, lpfc_cmd); else ret = FAILED; - } else if (status == IOCB_TIMEDOUT) { + } else if ((status == IOCB_TIMEDOUT) || + (status == IOCB_ABORTED)) { ret = TIMEOUT_ERROR; } else { ret = FAILED; @@ -5097,7 +6652,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, lpfc_sli_release_iocbq(phba, iocbqrsp); - if (ret != TIMEOUT_ERROR) + if (status != IOCB_TIMEDOUT) lpfc_release_scsi_buf(phba, lpfc_cmd); return ret; @@ -5186,7 +6741,7 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); } if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0724 I/O flush failure for context %s : cnt x%x\n", ((context == LPFC_CTX_LUN) ? "LUN" : ((context == LPFC_CTX_TGT) ? "TGT" : @@ -5212,17 +6767,18 @@ static int lpfc_device_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_rport_data *rdata; struct lpfc_nodelist *pnode; unsigned tgt_id = cmnd->device->id; uint64_t lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; - int status; + int status = 0; + u32 logit = LOG_FCP; rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0798 Device Reset rdata failure: rdata x%px\n", rdata); return FAILED; @@ -5234,7 +6790,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0721 Device Reset rport failure: rdata x%px\n", rdata); return FAILED; } @@ -5250,8 +6806,10 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id, FCP_LUN_RESET); + if (status != SUCCESS) + logit = LOG_TRACE_EVENT; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, logit, "0713 SCSI layer issued Device Reset (%d, %llu) " "return x%x\n", tgt_id, lun_id, status); @@ -5289,11 +6847,15 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) unsigned tgt_id = cmnd->device->id; uint64_t lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; - int status; + int status = 0; + u32 logit = LOG_FCP; + u32 dev_loss_tmo = vport->cfg_devloss_tmo; + unsigned long flags; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0799 Target Reset rdata failure: rdata x%px\n", rdata); return FAILED; @@ -5305,13 +6867,13 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, flags); pnode->nlp_flag &= ~NLP_NPR_ADISC; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, flags); } lpfc_reset_flush_io_context(vport, tgt_id, lun_id, LPFC_CTX_TGT); @@ -5329,8 +6891,47 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id, FCP_TARGET_RESET); + if (status != SUCCESS) { + logit = LOG_TRACE_EVENT; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + /* Issue LOGO, if no LOGO is outstanding */ + spin_lock_irqsave(shost->host_lock, flags); + if (!(pnode->upcall_flags & NLP_WAIT_FOR_LOGO) && + !pnode->logo_waitq) { + pnode->logo_waitq = &waitq; + pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + pnode->nlp_flag |= NLP_ISSUE_LOGO; + pnode->upcall_flags |= NLP_WAIT_FOR_LOGO; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_unreg_rpi(vport, pnode); + wait_event_timeout(waitq, + (!(pnode->upcall_flags & + NLP_WAIT_FOR_LOGO)), + msecs_to_jiffies(dev_loss_tmo * + 1000)); + + if (pnode->upcall_flags & NLP_WAIT_FOR_LOGO) { + lpfc_printf_vlog(vport, KERN_ERR, logit, + "0725 SCSI layer TGTRST failed" + " & LOGO TMO (%d, %llu) " + "return x%x\n", + tgt_id, lun_id, status); + spin_lock_irqsave(shost->host_lock, flags); + pnode->upcall_flags &= ~NLP_WAIT_FOR_LOGO; + } else { + spin_lock_irqsave(shost->host_lock, flags); + } + pnode->logo_waitq = NULL; + spin_unlock_irqrestore(shost->host_lock, flags); + status = SUCCESS; + } else { + + spin_unlock_irqrestore(shost->host_lock, flags); + status = FAILED; + } + } + + lpfc_printf_vlog(vport, KERN_ERR, logit, "0723 SCSI layer issued Target Reset (%d, %llu) " "return x%x\n", tgt_id, lun_id, status); @@ -5365,7 +6966,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) struct lpfc_nodelist *ndlp = NULL; struct lpfc_scsi_event_header scsi_event; int match; - int ret = SUCCESS, status, i; + int ret = SUCCESS, status = SUCCESS, i; + u32 logit = LOG_FCP; scsi_event.event_type = FC_REG_SCSI_EVENT; scsi_event.subcategory = LPFC_EVENT_BUSRESET; @@ -5411,7 +7013,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) i, 0, FCP_TARGET_RESET); if (status != SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0700 Bus Reset on target %d failed\n", i); ret = FAILED; @@ -5427,8 +7029,10 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); if (status != SUCCESS) ret = FAILED; + if (ret == FAILED) + logit = LOG_TRACE_EVENT; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, logit, "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); return ret; } @@ -5474,7 +7078,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) return ret; error: - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3323 Failed host reset\n"); lpfc_unblock_mgmt_io(phba); return FAILED; @@ -5585,7 +7189,7 @@ lpfc_slave_alloc(struct scsi_device *sdev) } num_allocated = lpfc_new_scsi_buf_s3(vport, num_to_alloc); if (num_to_alloc != num_allocated) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0708 Allocation request of %d " "command buffers did not succeed. " "Allocated %d buffers.\n", @@ -5602,6 +7206,7 @@ lpfc_slave_alloc(struct scsi_device *sdev) * * This routine configures following items * - Tag command queuing support for @sdev if supported. + * - Dev loss time out value of fc_rport. * - Enable SLI polling for fcp ring if ENABLE_FCP_RING_POLLING flag is set. * * Return codes: @@ -5612,9 +7217,17 @@ lpfc_slave_configure(struct scsi_device *sdev) { struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; + struct fc_rport *rport = starget_to_rport(sdev->sdev_target); + + /* + * Initialize the fc transport attributes for the target + * containing this scsi device. Also note that the driver's + * target pointer is stored in the starget_data for the + * driver's sysfs entry point functions. + */ + rport->dev_loss_tmo = vport->cfg_devloss_tmo; scsi_change_queue_depth(sdev, vport->cfg_lun_queue_depth); - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); @@ -6016,44 +7629,21 @@ struct scsi_host_template lpfc_template_nvme = { .this_id = -1, .sg_tablesize = 1, .cmd_per_lun = 1, +#if (KERNEL_MAJOR < 5) + .use_clustering = ENABLE_CLUSTERING, +#endif .shost_attrs = lpfc_hba_attrs, .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .track_queue_depth = 0, }; -struct scsi_host_template lpfc_template_no_hr = { - .module = THIS_MODULE, - .name = LPFC_DRIVER_NAME, - .proc_name = LPFC_DRIVER_NAME, - .info = lpfc_info, - .queuecommand = lpfc_queuecommand, - .eh_timed_out = fc_eh_timed_out, - .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler = lpfc_device_reset_handler, - .eh_target_reset_handler = lpfc_target_reset_handler, - .eh_bus_reset_handler = lpfc_bus_reset_handler, - .slave_alloc = lpfc_slave_alloc, - .slave_configure = lpfc_slave_configure, - .slave_destroy = lpfc_slave_destroy, - .scan_finished = lpfc_scan_finished, - .this_id = -1, - .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, - .cmd_per_lun = LPFC_CMD_PER_LUN, - .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFFFFFF, - .vendor_id = LPFC_NL_VENDOR_ID, - .change_queue_depth = scsi_change_queue_depth, - .track_queue_depth = 1, -}; - struct scsi_host_template lpfc_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, .proc_name = LPFC_DRIVER_NAME, .info = lpfc_info, .queuecommand = lpfc_queuecommand, - .eh_timed_out = fc_eh_timed_out, .eh_abort_handler = lpfc_abort_handler, .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, @@ -6066,32 +7656,12 @@ struct scsi_host_template lpfc_template = { .this_id = -1, .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, +#if (KERNEL_MAJOR < 5) + .use_clustering = ENABLE_CLUSTERING, +#endif .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, + .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, .track_queue_depth = 1, }; - -struct scsi_host_template lpfc_vport_template = { - .module = THIS_MODULE, - .name = LPFC_DRIVER_NAME, - .proc_name = LPFC_DRIVER_NAME, - .info = lpfc_info, - .queuecommand = lpfc_queuecommand, - .eh_timed_out = fc_eh_timed_out, - .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler = lpfc_device_reset_handler, - .eh_target_reset_handler = lpfc_target_reset_handler, - .slave_alloc = lpfc_slave_alloc, - .slave_configure = lpfc_slave_configure, - .slave_destroy = lpfc_slave_destroy, - .scan_finished = lpfc_scan_finished, - .this_id = -1, - .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, - .cmd_per_lun = LPFC_CMD_PER_LUN, - .shost_attrs = lpfc_vport_attrs, - .max_sectors = 0xFFFF, - .change_queue_depth = scsi_change_queue_depth, - .track_queue_depth = 1, -}; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index f76667b7d..3bdbfcad8 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -2,7 +2,7 @@ * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc and/or its subsidiaries. * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -24,6 +24,9 @@ struct lpfc_hba; #define LPFC_FCP_CDB_LEN 16 +#define CTRL_ID 0 +#define LPFC_DATA_SIZE 255 +#define LPFC_FCP_FB_MAX 65536 #define list_remove_head(list, entry, type, member) \ do { \ @@ -130,6 +133,28 @@ struct lpfc_scsicmd_bkt { uint32_t cmd_count; }; +struct lpfc_scsi_io_req { + u32 dev_id; + u32 cmd_id; + void (*cmd_cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *p_io_in, + struct lpfc_iocbq *p_io_out); +}; + +struct lpfc_first_burst_page { + u8 page_code; + u8 page_len; + u8 buf_full_r; + u8 buf_mt_r; + __be16 bus_inact_lmt; + __be16 disc_tmo; + __be16 conn_tmo; + __be16 max_burst; + u8 byte12; + u8 rsvd; + __be16 first_burst; +}; + +#define LPFC_RETRY_PAUSE 300 #define LPFC_SCSI_DMA_EXT_SIZE 264 #define LPFC_BPL_SIZE 1024 #define MDAC_DIRECT_CMD 0x22 @@ -138,12 +163,65 @@ struct lpfc_scsicmd_bkt { #define NO_MORE_OAS_LUN -1 #define NOT_OAS_ENABLED_LUN NO_MORE_OAS_LUN +#ifndef WRITE_SAME_16 +#define WRITE_SAME_16 0x93 +#endif + +#ifndef VERIFY_12 +#define VERIFY_12 0xaf +#endif + +/* ASC/ASCQ codes used in driver */ +#define LPFC_ASC_DIF_ERR 0x10 +#define LPFC_ASCQ_GUARD_CHECK 0x1 +#define LPFC_ASCQ_REFTAG_CHECK 0x3 +#define LPFC_ASC_TARGET_CHANGED 0x3f +#define LPFC_ASCQ_INQUIRY_DATA 0x3 +#define LPFC_ASC_DATA_PHASE_ERR 0x4b +#define LPFC_ASCQ_EDIF_MODE 0x82 + +/* This macro is available from RHEL 7.1 onwards. */ +#ifndef FC_PORTSPEED_32GBIT +#define FC_PORTSPEED_32GBIT 0x40 +#endif + +#ifndef FC_PORTSPEED_64GBIT +#define FC_PORTSPEED_64GBIT 0x1000 +#endif + +#ifndef FC_PORTSPEED_25GBIT +#define FC_PORTSPEED_25GBIT 0x800 +#endif + +#ifndef FC_PORTSPEED_40GBIT +#define FC_PORTSPEED_40GBIT 0x100 +#endif + +#ifndef FC_PORTSPEED_100GBIT +#define FC_PORTSPEED_100GBIT 0x400 +#endif + #ifndef FC_PORTSPEED_128GBIT #define FC_PORTSPEED_128GBIT 0x2000 #endif #define TXRDY_PAYLOAD_LEN 12 +/* Safe command codes for scanning, excluding group code */ +#define LPFC_INQUIRY_CMD_CODE (INQUIRY & 0x1f) +#define LPFC_LOG_SELECT_CMD_CODE (LOG_SELECT & 0x1f) +#define LPFC_LOG_SENSE_CMD_CODE (LOG_SENSE & 0x1f) +#define LPFC_MODE_SELECT_CMD_CODE (MODE_SELECT & 0x1f) +#define LPFC_MODE_SENSE_CMD_CODE (MODE_SENSE & 0x1f) +#define LPFC_REPORT_LUNS_CMD_CODE (REPORT_LUNS & 0x1f) +#define LPFC_SEND_DIAGNOSTIC_CMD_CODE (SEND_DIAGNOSTIC & 0x1f) +#define LPFC_MAINTENANCE_IN_CMD_CODE (MAINTENANCE_IN & 0x1f) +#define LPFC_MAINTENANCE_OUT_CMD_CODE (MAINTENANCE_OUT & 0x1f) +#define LPFC_PERSISTENT_RESERVE_IN_CMD_CODE (PERSISTENT_RESERVE_IN & 0x1f) +#define LPFC_PERSISTENT_RESERVE_OUT_CMD_CODE (PERSISTENT_RESERVE_OUT & 0x1f) +#define LPFC_READ_BUFFER_CMD_CODE (READ_BUFFER & 0x1f) +#define LPFC_WRITE_BUFFER_CMD_CODE (WRITE_BUFFER & 0x1f) + /* For sysfs/debugfs tmp string max len */ #define LPFC_MAX_SCSI_INFO_TMP_LEN 79 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ef7cef316..c0f9d4fe3 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -35,11 +34,12 @@ #include #include #include -#ifdef CONFIG_X86 -#include -#endif - +#include +#if defined(BUILD_NVME) +#if (IS_ENABLED(CONFIG_NVME_FC)) #include +#endif +#endif #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -87,6 +87,13 @@ static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe); static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba); static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba); +static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q); +static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba, + struct lpfc_queue *cq, + struct lpfc_cqe *cqe); + +extern int lpfc_fabric_cgn_frequency; +extern int lpfc_acqe_cgn_frequency; static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -138,12 +145,15 @@ static int lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) { union lpfc_wqe *temp_wqe; + struct lpfc_hba *phba = q->phba; struct lpfc_register doorbell; uint32_t host_index; uint32_t idx; +#ifndef BUILD_BRCMFCOE uint32_t i = 0; uint8_t *tmp; u32 if_type; +#endif /* sanity check on queue memory */ if (unlikely(!q)) @@ -153,6 +163,10 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* If the host has not yet processed the next entry then we are done */ idx = ((q->host_index + 1) % q->entry_count); if (idx == q->hba_index) { + lpfc_throttle_log(q->phba, &q->phba->pport->log, LOG_SLI, + "9998 WQ failure. WQ Full. " + "q_id x%x, host x%x, hba x%x\n", + q->queue_id, idx, q->hba_index); q->WQ_overflow++; return -EBUSY; } @@ -162,22 +176,22 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); else bf_set(wqe_wqec, &wqe->generic.wqe_com, 0); - if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) + if (phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli4_pcimem_bcopy(wqe, temp_wqe, q->entry_size); - if (q->dpp_enable && q->phba->cfg_enable_dpp) { +#ifndef BUILD_BRCMFCOE + if (q->dpp_enable && phba->cfg_enable_dpp) { /* write to DPP aperture taking advatage of Combined Writes */ - tmp = (uint8_t *)temp_wqe; -#ifdef __raw_writeq + tmp = (uint8_t *)wqe; +#if defined(CONFIG_64BIT) && defined(__LITTLE_ENDIAN) for (i = 0; i < q->entry_size; i += sizeof(uint64_t)) - __raw_writeq(*((uint64_t *)(tmp + i)), - q->dpp_regaddr + i); + writeq(*((uint64_t *)(tmp + i)), q->dpp_regaddr + i); #else for (i = 0; i < q->entry_size; i += sizeof(uint32_t)) - __raw_writel(*((uint32_t *)(tmp + i)), - q->dpp_regaddr + i); + writel(*((uint32_t *)(tmp + i)), q->dpp_regaddr + i); #endif } +#endif /* ensure WQE bcopy and DPP flushed before doorbell write */ wmb(); @@ -189,7 +203,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* Ring Doorbell */ doorbell.word0 = 0; if (q->db_format == LPFC_DB_LIST_FORMAT) { - if (q->dpp_enable && q->phba->cfg_enable_dpp) { +#ifndef BUILD_BRCMFCOE + if (q->dpp_enable && phba->cfg_enable_dpp) { bf_set(lpfc_if6_wq_db_list_fm_num_posted, &doorbell, 1); bf_set(lpfc_if6_wq_db_list_fm_dpp, &doorbell, 1); bf_set(lpfc_if6_wq_db_list_fm_dpp_id, &doorbell, @@ -202,11 +217,16 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* Leave bits <23:16> clear for if_type 6 dpp */ if_type = bf_get(lpfc_sli_intf_if_type, - &q->phba->sli4_hba.sli_intf); + &phba->sli4_hba.sli_intf); if (if_type != LPFC_SLI_INTF_IF_TYPE_6) bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index); } +#else + bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1); + bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index); + bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id); +#endif } else if (q->db_format == LPFC_DB_RING_FORMAT) { bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1); bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id); @@ -226,25 +246,16 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) * This routine will update the HBA index of a queue to reflect consumption of * Work Queue Entries by the HBA. When the HBA indicates that it has consumed * an entry the host calls this function to update the queue's internal - * pointers. This routine returns the number of entries that were consumed by - * the HBA. + * pointers. **/ -static uint32_t +static void lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) { - uint32_t released = 0; - /* sanity check on queue memory */ if (unlikely(!q)) - return 0; + return; - if (q->hba_index == index) - return 0; - do { - q->hba_index = ((q->hba_index + 1) % q->entry_count); - released++; - } while (q->hba_index != index); - return released; + q->hba_index = index; } /** @@ -415,7 +426,7 @@ lpfc_sli4_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q, bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); /* PCI read to flush PCI pipeline on re-arming for INTx mode */ - if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) + if (q->phba->intr_type == INTx && arm == LPFC_QUEUE_REARM) readl(q->phba->sli4_hba.EQDBregaddr); } @@ -442,13 +453,14 @@ lpfc_sli4_if6_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q, /* ring doorbell for number popped */ doorbell.word0 = 0; - if (arm) + if (arm) { bf_set(lpfc_if6_eq_doorbell_arm, &doorbell, 1); + } bf_set(lpfc_if6_eq_doorbell_num_released, &doorbell, count); bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); /* PCI read to flush PCI pipeline on re-arming for INTx mode */ - if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) + if (q->phba->intr_type == INTx && arm == LPFC_QUEUE_REARM) readl(q->phba->sli4_hba.EQDBregaddr); } @@ -467,21 +479,47 @@ __lpfc_sli4_consume_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, } static void -lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) +lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) { - struct lpfc_eqe *eqe; - uint32_t count = 0; + struct lpfc_eqe *eqe = NULL; + u32 eq_count = 0, cq_count = 0; + struct lpfc_cqe *cqe = NULL; + struct lpfc_queue *cq = NULL, *childq = NULL; + int cqid = 0; /* walk all the EQ entries and drop on the floor */ eqe = lpfc_sli4_eq_get(eq); while (eqe) { + /* Get the reference to the corresponding CQ */ + cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); + cq = NULL; + + list_for_each_entry(childq, &eq->child_list, list) { + if (childq->queue_id == cqid) { + cq = childq; + break; + } + } + /* If CQ is valid, iterate through it and drop all the CQEs */ + if (cq) { + cqe = lpfc_sli4_cq_get(cq); + while (cqe) { + __lpfc_sli4_consume_cqe(phba, cq, cqe); + cq_count++; + cqe = lpfc_sli4_cq_get(cq); + } + /* Clear and re-arm the CQ */ + phba->sli4_hba.sli4_write_cq_db(phba, cq, cq_count, + LPFC_QUEUE_REARM); + cq_count = 0; + } __lpfc_sli4_consume_eqe(phba, eq, eqe); - count++; + eq_count++; eqe = lpfc_sli4_eq_get(eq); } /* Clear and re-arm the EQ */ - phba->sli4_hba.sli4_write_eq_db(phba, eq, count, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_write_eq_db(phba, eq, eq_count, LPFC_QUEUE_REARM); } static int @@ -517,7 +555,7 @@ lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq, if (count > eq->EQ_max_eqe) eq->EQ_max_eqe = count; - eq->queue_claimed = 0; + xchg(&eq->queue_claimed, 0); rearm_and_exit: /* Always clear the EQ. */ @@ -777,8 +815,6 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; struct lpfc_iocbq * iocbq = NULL; - lockdep_assert_held(&phba->hbalock); - list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list); if (iocbq) phba->iocb_cnt++; @@ -992,9 +1028,10 @@ lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * @ndlp: Targets nodelist pointer for this exchange. * @xritag the xri in the bitmap to test. * - * This function returns: - * 0 = rrq not active for this xri - * 1 = rrq is valid for this xri. + * This function relies on the atomic test_bit and does + * not require a lock. + * returns 0 = rrq not active for this xri + * 1 = rrq is valid for this xri. **/ int lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, @@ -1061,7 +1098,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto out; spin_unlock_irqrestore(&phba->hbalock, iflags); - rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL); + rrq = mempool_alloc(phba->rrq_pool, GFP_ATOMIC); if (!rrq) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3155 Unable to allocate RRQ xri:0x%x rxid:0x%x" @@ -1102,11 +1139,10 @@ out: * @phba: Pointer to HBA context object. * @piocb: Pointer to the iocbq. * - * The driver calls this function with either the nvme ls ring lock - * or the fc els ring lock held depending on the iocb usage. This function - * gets a new driver sglq object from the sglq list. If the list is not empty - * then it is successful, it returns pointer to the newly allocated sglq - * object else it returns NULL. + * This function is called with the ELS ring lock held. This function + * gets a new driver sglq object from the sglq list. If the + * list is not empty then it is successful, it returns pointer to the newly + * allocated sglq object else it returns NULL. **/ static struct lpfc_sglq * __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) @@ -1116,15 +1152,8 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) struct lpfc_sglq *start_sglq = NULL; struct lpfc_io_buf *lpfc_cmd; struct lpfc_nodelist *ndlp; - struct lpfc_sli_ring *pring = NULL; int found = 0; - if (piocbq->iocb_flag & LPFC_IO_NVME_LS) - pring = phba->sli4_hba.nvmels_wq->pring; - else - pring = lpfc_phba_elsring(phba); - - lockdep_assert_held(&pring->ring_lock); if (piocbq->iocb_flag & LPFC_IO_FCP) { lpfc_cmd = (struct lpfc_io_buf *) piocbq->context1; @@ -1248,8 +1277,6 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) unsigned long iflag = 0; struct lpfc_sli_ring *pring; - lockdep_assert_held(&phba->hbalock); - if (iocbq->sli4_xritag == NO_XRI) sglq = NULL; else @@ -1301,7 +1328,7 @@ out: memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); iocbq->sli4_lxritag = NO_XRI; iocbq->sli4_xritag = NO_XRI; - iocbq->iocb_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | + iocbq->iocb_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | LPFC_IO_CMF | LPFC_IO_NVME_LS); list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); } @@ -1322,8 +1349,6 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - lockdep_assert_held(&phba->hbalock); - /* * Clean all volatile data fields, preserve iotag and node struct. */ @@ -1345,8 +1370,6 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) static void __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { - lockdep_assert_held(&phba->hbalock); - phba->__lpfc_sli_release_iocbq(phba, iocbq); phba->iocb_cnt--; } @@ -1392,15 +1415,19 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist, while (!list_empty(iocblist)) { list_remove_head(iocblist, piocb, struct lpfc_iocbq, list); - if (!piocb->iocb_cmpl) { - if (piocb->iocb_flag & LPFC_IO_NVME) - lpfc_nvme_cancel_iocb(phba, piocb); - else + if (piocb->wqe_cmpl) { + if (piocb->iocb_flag & LPFC_IO_NVME) { + lpfc_nvme_cancel_iocb(phba, piocb, + ulpstatus, ulpWord4); + } else { lpfc_sli_release_iocbq(phba, piocb); - } else { + } + } else if (piocb->iocb_cmpl) { piocb->iocb.ulpStatus = ulpstatus; piocb->iocb.un.ulpWord[4] = ulpWord4; (piocb->iocb_cmpl) (phba, piocb, piocb); + } else { + lpfc_sli_release_iocbq(phba, piocb); } } return; @@ -1475,6 +1502,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case DSSCMD_IWRITE64_CX: case DSSCMD_IREAD64_CR: case DSSCMD_IREAD64_CX: + case CMD_SEND_FRAME: type = LPFC_SOL_IOCB; break; case CMD_ABORT_XRI_CN: @@ -1549,7 +1577,7 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) lpfc_config_ring(phba, i, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0446 Adapter failed to init (%d), " "mbxCmd x%x CFG_RING, mbxStatus x%x, " "ring %d\n", @@ -1570,23 +1598,19 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) * @pring: Pointer to driver SLI ring object. * @piocb: Pointer to the driver iocb object. * - * The driver calls this function with the hbalock held for SLI3 ports or - * the ring lock held for SLI4 ports. The function adds the - * new iocb to txcmplq of the given ring. This function always returns - * 0. If this function is called for ELS ring, this function checks if - * there is a vport associated with the ELS command. This function also - * starts els_tmofunc timer if this is an ELS command. + * This function is called with hbalock(sli3) or the ringlock(sli4) + * held. The function adds the new iocb to txcmplq of the given ring. + * This function always returns 0. If this function is called for ELS + * ring, this function checks if there is a vport associated with the + * ELS command. This function also starts els_tmofunc timer if this is + * an ELS command. **/ static int lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { - if (phba->sli_rev == LPFC_SLI_REV4) - lockdep_assert_held(&pring->ring_lock); - else - lockdep_assert_held(&phba->hbalock); - BUG_ON(!piocb); + BUG_ON(!piocb || !piocb->vport); list_add_tail(&piocb->list, &pring->txcmplq); piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ; @@ -1594,13 +1618,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if ((unlikely(pring->ringno == LPFC_ELS_RING)) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { - BUG_ON(!piocb->vport); - if (!(piocb->vport->load_flag & FC_UNLOADING)) - mod_timer(&piocb->vport->els_tmofunc, - jiffies + - msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); - } + (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) && + (!(piocb->vport->load_flag & FC_UNLOADING))) + mod_timer(&piocb->vport->els_tmofunc, + jiffies + + msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); return 0; } @@ -1620,12 +1642,256 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { struct lpfc_iocbq *cmd_iocb; - lockdep_assert_held(&phba->hbalock); - list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list); return cmd_iocb; } +/** + * lpfc_cmf_sync_cmpl - Process a CMF_SYNC_WQE cmpl + * @phba: Pointer to HBA context object. + * @cmdiocb: Pointer to driver command iocb object. + * @cmf_cmpl: Pointer to driver response cqe object. + * + * This routine will inform the driver of any BW adjustments we need + * to make. These changes will be picked up during the next CMF + * timer interrupt. In addition, any BW changes will be logged + * with LOG_CGN_MGMT. + **/ +void +lpfc_cmf_sync_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_wcqe_complete *cmf_cmpl) +{ + union lpfc_wqe128 *wqe; + uint32_t status, info; + uint64_t bw, bwdif, slop; + uint64_t pcent, bwpcent; + int asig, afpin, sigcnt, fpincnt; + int wsigmax, wfpinmax, cg, tdp; + char *s; + + /* First check for error */ + status = bf_get(lpfc_wcqe_c_status, cmf_cmpl); + if (status) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6211 CMF_SYNC_WQE Error " + "req_tag x%x status x%x hwstatus x%x " + "tdatap x%x parm x%x\n", + bf_get(lpfc_wcqe_c_request_tag, cmf_cmpl), + bf_get(lpfc_wcqe_c_status, cmf_cmpl), + bf_get(lpfc_wcqe_c_hw_status, cmf_cmpl), + cmf_cmpl->total_data_placed, + cmf_cmpl->parameter); + goto out; + } + + /* Gather congestion information on a successful cmpl */ + info = cmf_cmpl->parameter; + phba->cmf_active_info = info; + + /* See if firmware info count is valid or has changed */ + if (info > LPFC_MAX_CMF_INFO || phba->cmf_info_per_interval == info) + info = 0; + else + phba->cmf_info_per_interval = info; + + tdp = bf_get(lpfc_wcqe_c_cmf_bw, cmf_cmpl); + cg = bf_get(lpfc_wcqe_c_cmf_cg, cmf_cmpl); + + /* Get BW requirement from firmware */ + bw = (uint64_t)tdp * LPFC_CMF_BLK_SIZE; + if (!bw) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6212 CMF_SYNC_WQE x%x: NULL bw\n", + bf_get(lpfc_wcqe_c_request_tag, cmf_cmpl)); + goto out; + } + + /* Gather information needed for logging if a BW change is required */ + wqe = &cmdiocb->wqe; + asig = bf_get(cmf_sync_asig, &wqe->cmf_sync); + afpin = bf_get(cmf_sync_afpin, &wqe->cmf_sync); + fpincnt = bf_get(cmf_sync_wfpincnt, &wqe->cmf_sync); + sigcnt = bf_get(cmf_sync_wsigcnt, &wqe->cmf_sync); + if (phba->cmf_max_bytes_per_interval != bw || + (asig || afpin || sigcnt || fpincnt)) { + /* Are we increasing or decreasing BW */ + if (phba->cmf_max_bytes_per_interval < bw) { + bwdif = bw - phba->cmf_max_bytes_per_interval; + s = "Increase"; + } else { + bwdif = phba->cmf_max_bytes_per_interval - bw; + s = "Decrease"; + } + + /* What is the change percentage */ + slop = (phba->cmf_link_byte_count / 200); /* For rounding */ + pcent = ((bwdif * 100) + slop) / phba->cmf_link_byte_count; + bwpcent = ((bw * 100) + slop) / phba->cmf_link_byte_count; + if (asig) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6237 BW Threshold %lld%% (%lld): " + "%lld%% %s: Signal Alarm: cg:%d " + "Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } else if (afpin) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6238 BW Threshold %lld%% (%lld): " + "%lld%% %s: FPIN Alarm: cg:%d " + "Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } else if (sigcnt) { + wsigmax = bf_get(cmf_sync_wsigmax, &wqe->cmf_sync); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6239 BW Threshold %lld%% (%lld): " + "%lld%% %s: Signal Warning: " + "Cnt %d Max %d: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, sigcnt, + wsigmax, cg, phba->cmf_active_info); + } else if (fpincnt) { + wfpinmax = bf_get(cmf_sync_wfpinmax, &wqe->cmf_sync); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6240 BW Threshold %lld%% (%lld): " + "%lld%% %s: FPIN Warning: " + "Cnt %d Max %d: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, fpincnt, + wfpinmax, cg, phba->cmf_active_info); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6241 BW Threshold %lld%% (%lld): " + "CMF %lld%% %s: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } + } else if (info) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6246 Info Threshold %u\n", info); + } + + /* Save BW change to be picked up during next timer interrupt */ + phba->cmf_last_sync_bw = bw; +out: + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** + * lpfc_issue_cmf_sync_wqe - Issue a CMF_SYNC_WQE + * @phba: Pointer to HBA context object. + * @ms: ms to set in WQE interval, 0 means use init op + * @total Total rcv bytes for this interval + * + * This routine is called every CMF timer interrupt. Its purpose is + * to issue a CMF_SYNC_WQE to the firmware to inform it of any events + * that may indicate we have congestion (FPINs or Signals). Upon + * completion, the firmware will indicate any BW restrictions the + * driver may need to take. + **/ +int +lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total) +{ + union lpfc_wqe128 *wqe; + struct lpfc_iocbq *sync_buf; + unsigned long iflags; + u32 ret_val; + u32 atot, wtot, max; + + /* First address any alarm / warning activity */ + atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0); + wtot = atomic_xchg(&phba->cgn_sync_warn_cnt, 0); + + /* ONLY Managed mode will send the CMF_SYNC_WQE to the HBA */ + if (phba->cmf_active_mode != LPFC_CFG_MANAGED || + phba->link_state == LPFC_LINK_DOWN) + return 0; + + spin_lock_irqsave(&phba->hbalock, iflags); + sync_buf = __lpfc_sli_get_iocbq(phba); + if (!sync_buf) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6213 No available WQEs for CMF_SYNC_WQE\n"); + ret_val = ENOMEM; + goto out_unlock; + } + + wqe = &sync_buf->wqe; + + /* WQEs are reused. Clear stale data and set key fields to zero */ + memset(wqe, 0, sizeof(*wqe)); + + /* If this is the very first CMF_SYNC_WQE, issue an init operation */ + if (!ms) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6441 CMF Init %d - CMF_SYNC_WQE\n", + phba->fc_eventTag); + bf_set(cmf_sync_op, &wqe->cmf_sync, 1); /* 1=init */ + bf_set(cmf_sync_interval, &wqe->cmf_sync, LPFC_CMF_INTERVAL); + goto initpath; + } + + bf_set(cmf_sync_op, &wqe->cmf_sync, 0); /* 0=recalc */ + bf_set(cmf_sync_interval, &wqe->cmf_sync, ms); + + /* Check for alarms / warnings */ + if (atot) { + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + /* We hit an Signal alarm condition */ + bf_set(cmf_sync_asig, &wqe->cmf_sync, 1); + } else { + /* We hit a FPIN alarm condition */ + bf_set(cmf_sync_afpin, &wqe->cmf_sync, 1); + } + } else if (wtot) { + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + /* We hit an Signal warning condition */ + max = LPFC_SEC_TO_MSEC / lpfc_fabric_cgn_frequency * + lpfc_acqe_cgn_frequency; + bf_set(cmf_sync_wsigmax, &wqe->cmf_sync, max); + bf_set(cmf_sync_wsigcnt, &wqe->cmf_sync, wtot); + } else { + /* We hit a FPIN warning condition */ + bf_set(cmf_sync_wfpinmax, &wqe->cmf_sync, 1); + bf_set(cmf_sync_wfpincnt, &wqe->cmf_sync, 1); + } + } + + /* Update total read blocks during previous timer interval */ + wqe->cmf_sync.read_bytes = (u32)(total / LPFC_CMF_BLK_SIZE); + +initpath: + bf_set(cmf_sync_ver, &wqe->cmf_sync, LPFC_CMF_SYNC_VER); + wqe->cmf_sync.event_tag = phba->fc_eventTag; + bf_set(cmf_sync_cmnd, &wqe->cmf_sync, CMD_CMF_SYNC_WQE); + + /* Setup reqtag to match the wqe completion. */ + bf_set(cmf_sync_reqtag, &wqe->cmf_sync, sync_buf->iotag); + + bf_set(cmf_sync_qosd, &wqe->cmf_sync, 1); + + bf_set(cmf_sync_cmd_type, &wqe->cmf_sync, CMF_SYNC_COMMAND); + bf_set(cmf_sync_wqec, &wqe->cmf_sync, 1); + bf_set(cmf_sync_cqid, &wqe->cmf_sync, LPFC_WQE_CQ_ID_DEFAULT); + + sync_buf->vport = phba->pport; + sync_buf->wqe_cmpl = lpfc_cmf_sync_cmpl; + sync_buf->iocb_cmpl = NULL; + sync_buf->context1 = NULL; + sync_buf->context2 = NULL; + sync_buf->context3 = NULL; + sync_buf->sli4_xritag = NO_XRI; + + sync_buf->iocb_flag |= LPFC_IO_CMF; + ret_val = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], sync_buf); + if (ret_val) + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6214 Cannot issue CMF_SYNC_WQE: x%x\n", + ret_val); +out_unlock: + spin_unlock_irqrestore(&phba->hbalock, iflags); + return ret_val; +} + /** * lpfc_sli_next_iocb_slot - Get next iocb slot in the ring * @phba: Pointer to HBA context object. @@ -1646,8 +1912,6 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; uint32_t max_cmd_idx = pring->sli.sli3.numCiocb; - lockdep_assert_held(&phba->hbalock); - if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) && (++pring->sli.sli3.next_cmdidx >= max_cmd_idx)) pring->sli.sli3.next_cmdidx = 0; @@ -1658,7 +1922,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); if (unlikely(pring->sli.sli3.local_getidx >= max_cmd_idx)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0315 Ring %d issue: portCmdGet %d " "is bigger than cmd ring %d\n", pring->ringno, @@ -1718,7 +1982,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) - LPFC_IOCBQ_LOOKUP_INCREMENT)) { new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT; spin_unlock_irq(&phba->hbalock); - new_arr = kcalloc(new_len, sizeof(struct lpfc_iocbq *), + new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *), GFP_KERNEL); if (new_arr) { spin_lock_irq(&phba->hbalock); @@ -1768,7 +2032,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) * @nextiocb: Pointer to driver iocb object which need to be * posted to firmware. * - * This function is called with hbalock held to post a new iocb to + * This function is called from the normal IO path and from the ISR. * the firmware. This function copies the new iocb to ring iocb slot and * updates the ring pointers. It adds the new iocb to txcmplq if there is * a completion call back for this iocb else the function will free the @@ -1778,7 +2042,6 @@ static void lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t *iocb, struct lpfc_iocbq *nextiocb) { - lockdep_assert_held(&phba->hbalock); /* * Set up an iotag */ @@ -1878,7 +2141,8 @@ lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. * - * This function is called with hbalock held to post pending iocbs + * This function is called from the normal IO path and from + * within the isr code path. * in the txq to the firmware. This function is called when driver * detects space available in the ring. **/ @@ -1888,7 +2152,6 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) IOCB_t *iocb; struct lpfc_iocbq *nextiocb; - lockdep_assert_held(&phba->hbalock); /* * Check to see if: @@ -1931,8 +2194,6 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) { struct hbq_s *hbqp = &phba->hbqs[hbqno]; - lockdep_assert_held(&phba->hbalock); - if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx && ++hbqp->next_hbqPutIdx >= hbqp->entry_count) hbqp->next_hbqPutIdx = 0; @@ -1944,8 +2205,7 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) hbqp->local_hbqGetIdx = getidx; if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1802 HBQ %d: local_hbqGetIdx " "%u is > than hbqp->entry_count %u\n", hbqno, hbqp->local_hbqGetIdx, @@ -2014,7 +2274,6 @@ static int lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, struct hbq_dmabuf *hbq_buf) { - lockdep_assert_held(&phba->hbalock); return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf); } @@ -2036,7 +2295,6 @@ lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno, struct lpfc_hbq_entry *hbqe; dma_addr_t physaddr = hbq_buf->dbuf.phys; - lockdep_assert_held(&phba->hbalock); /* Get next HBQ entry slot to use */ hbqe = lpfc_sli_next_hbq_slot(phba, hbqno); if (hbqe) { @@ -2084,7 +2342,6 @@ lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno, hrq = phba->sli4_hba.hdr_rq; drq = phba->sli4_hba.dat_rq; - lockdep_assert_held(&phba->hbalock); hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys); hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys); drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys); @@ -2284,7 +2541,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) } } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1803 Bad hbq tag. Data: x%x x%x\n", tag, phba->hbqs[tag >> 16].buffer_count); return NULL; @@ -2538,7 +2795,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check security permission status on INIT_LINK mailbox command */ if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) && (pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2860 SLI authentication is required " "for INIT_LINK but has not done yet\n"); @@ -2674,10 +2931,11 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) == MBX_SHUTDOWN) { /* Unknown mailbox command compl */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0323 Unknown Mailbox command " "x%x (x%x/x%x) Cmpl\n", - pmb->vport ? pmb->vport->vpi : 0, + pmb->vport ? pmb->vport->vpi : + LPFC_VPORT_UNKNOWN, pmbox->mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, pmb), @@ -2698,7 +2956,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) "(%d):0305 Mbox cmd cmpl " "error - RETRYing Data: x%x " "(x%x/x%x) x%x x%x x%x\n", - pmb->vport ? pmb->vport->vpi : 0, + pmb->vport ? pmb->vport->vpi : + LPFC_VPORT_UNKNOWN, pmbox->mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, pmb), @@ -2706,7 +2965,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) pmb), pmbox->mbxStatus, pmbox->un.varWords[0], - pmb->vport->port_state); + pmb->vport ? pmb->vport->port_state : + LPFC_VPORT_UNKNOWN); pmbox->mbxStatus = 0; pmbox->mbxOwner = OWN_HOST; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); @@ -2999,8 +3259,11 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * * This function looks up the iocb_lookup table to get the command iocb * corresponding to the given response iocb using the iotag of the - * response iocb. The driver calls this function with the hbalock held - * for SLI3 ports or the ring lock held for SLI4 ports. + * response iocb. This function is called with the hbalock held + * for sli3 devices or the ring_lock for sli4 devices. + * except when the LPFC_FCP_POLLING module parameter is set and + * lpfc_queuecommand + * call the lpfc_handle_fast_ring_event. * This function returns the command iocb object if it finds the command * iocb else returns NULL. **/ @@ -3011,15 +3274,7 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, { struct lpfc_iocbq *cmd_iocb = NULL; uint16_t iotag; - spinlock_t *temp_lock = NULL; - unsigned long iflag = 0; - if (phba->sli_rev == LPFC_SLI_REV4) - temp_lock = &pring->ring_lock; - else - temp_lock = &phba->hbalock; - - spin_lock_irqsave(temp_lock, iflag); iotag = prspiocb->iocb.ulpIoTag; if (iotag != 0 && iotag <= phba->sli.last_iotag) { @@ -3029,13 +3284,11 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, list_del_init(&cmd_iocb->list); cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; - spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } - spin_unlock_irqrestore(temp_lock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0317 iotag x%x is out of " "range: max iotag x%x wd0 x%x\n", iotag, phba->sli.last_iotag, @@ -3050,8 +3303,8 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, * @iotag: IOCB tag. * * This function looks up the iocb_lookup table to get the command iocb - * corresponding to the given iotag. The driver calls this function with - * the ring lock held because this function is an SLI4 port only helper. + * corresponding to the given iotag. This function is called with the + * hbalock held. * This function returns the command iocb object if it finds the command * iocb else returns NULL. **/ @@ -3060,15 +3313,7 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint16_t iotag) { struct lpfc_iocbq *cmd_iocb = NULL; - spinlock_t *temp_lock = NULL; - unsigned long iflag = 0; - if (phba->sli_rev == LPFC_SLI_REV4) - temp_lock = &pring->ring_lock; - else - temp_lock = &phba->hbalock; - - spin_lock_irqsave(temp_lock, iflag); if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { @@ -3076,13 +3321,11 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, list_del_init(&cmd_iocb->list); cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; - spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } - spin_unlock_irqrestore(temp_lock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0372 iotag x%x lookup error: max iotag (x%x) " "iocb_flag x%x\n", iotag, phba->sli.last_iotag, @@ -3115,7 +3358,17 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int rc = 1; unsigned long iflag; + /* Based on the iotag field, get the cmd IOCB from the txcmplq */ + if (phba->sli_rev == LPFC_SLI_REV4) + spin_lock_irqsave(&pring->ring_lock, iflag); + else + spin_lock_irqsave(&phba->hbalock, iflag); cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); + if (phba->sli_rev == LPFC_SLI_REV4) + spin_unlock_irqrestore(&pring->ring_lock, iflag); + else + spin_unlock_irqrestore(&phba->hbalock, iflag); + if (cmdiocbp) { if (cmdiocbp->iocb_cmpl) { /* @@ -3258,7 +3511,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * Ring handler: portRspPut is bigger than * rsp ring */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0312 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, le32_to_cpu(pgp->rspPutInx), @@ -3288,13 +3541,21 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * and wake up worker thread to process it. Otherwise, it will set up the * Error Attention polling timer for the next poll. **/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_poll_eratt(unsigned long ptr) +#else void lpfc_poll_eratt(struct timer_list *t) +#endif { struct lpfc_hba *phba; uint32_t eratt = 0; uint64_t sli_intr, cnt; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + phba = (struct lpfc_hba *)ptr; +#else phba = from_timer(phba, t, eratt_poll); +#endif /* Here we will also keep track of interrupts per sec of the hba */ sli_intr = phba->sli.slistat.sli_intr; @@ -3446,14 +3707,10 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, break; } - spin_unlock_irqrestore(&phba->hbalock, iflag); cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); - spin_lock_irqsave(&phba->hbalock, iflag); if (unlikely(!cmdiocbq)) break; - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; if (cmdiocbq->iocb_cmpl) { spin_unlock_irqrestore(&phba->hbalock, iflag); (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, @@ -3477,7 +3734,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, phba->brd_no, adaptermsg); } else { /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0334 Unknown IOCB command " "Data: x%x, x%x x%x x%x x%x\n", type, irsp->ulpCommand, @@ -3643,12 +3900,9 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, case LPFC_ABORT_IOCB: cmdiocbp = NULL; - if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) { - spin_unlock_irqrestore(&phba->hbalock, iflag); + if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - } if (cmdiocbp) { /* Call the specified completion routine */ if (cmdiocbp->iocb_cmpl) { @@ -3675,7 +3929,7 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->brd_no, adaptermsg); } else { /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0335 Unknown IOCB " "command Data: x%x " "x%x x%x x%x\n", @@ -3755,7 +4009,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * Ring handler: portRspPut is bigger than * rsp ring */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0303 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, portRspPut, portRspMax); @@ -3957,6 +4211,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) lpfc_sli_issue_abort_iotag(phba, pring, iocb); spin_unlock_irq(&phba->hbalock); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, @@ -4127,7 +4383,7 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) /* Check to see if any errors occurred during init */ if ((status & HS_FFERM) || (i >= 20)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2751 Adapter failed to restart, " "status reg x%x, FW Data: A8 x%x AC x%x\n", status, @@ -4173,6 +4429,7 @@ lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask) } else phba->sli4_hba.intr_enable = 0; + phba->hba_flag &= ~HBA_SETUP; return retval; } @@ -4197,7 +4454,8 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) * @phba: Pointer to HBA context object. * * This function is called before resetting an HBA. This function is called - * with hbalock held and requests HBA to quiesce DMAs before a reset. + * from lpfc_work_list_done which releases the hbalock and then calls + * lpfc_reset_barrier to requests HBA to quiesce DMAs before a reset. **/ void lpfc_reset_barrier(struct lpfc_hba *phba) { @@ -4208,7 +4466,6 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) int i; uint8_t hdrtype; - lockdep_assert_held(&phba->hbalock); pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); if (hdrtype != 0x80 || @@ -4349,7 +4606,7 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) if (retval != MBX_SUCCESS) { if (retval != MBX_BUSY) mempool_free(pmb, phba->mbox_mem_pool); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2752 KILL_BOARD command failed retval %d\n", retval); spin_lock_irq(&phba->hbalock); @@ -4492,6 +4749,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; + phba->hba_flag &= ~HBA_SETUP; spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); @@ -4590,7 +4848,7 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); - psli->stats_start = ktime_get_seconds(); + psli->stats_start = get_seconds(); /* Give the INITFF and Post time to settle. */ mdelay(100); @@ -4641,7 +4899,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); - psli->stats_start = ktime_get_seconds(); + psli->stats_start = get_seconds(); /* Reset HBA AER if it was enabled, note hba_flag was reset above */ if (hba_aer_enabled) @@ -4701,7 +4959,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (i++ >= 200) { /* Adapter failed to init, timeout, status reg */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0436 Adapter failed to init, " "timeout, status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4716,7 +4974,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0437 Adapter failed to init, " "chipset, status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4747,7 +5005,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (status & HS_FFERM) { /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0438 Adapter failed to init, chipset, " "status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4892,8 +5150,17 @@ static int lpfc_sli4_rb_setup(struct lpfc_hba *phba) { phba->hbq_in_use = 1; - phba->hbqs[LPFC_ELS_HBQ].entry_count = - lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count; + /** + * Specific case when the MDS diagnostics is enabled and supported. + * The receive buffer count is truncated to manage the incoming + * traffic. + **/ + if (phba->cfg_enable_mds_diags && phba->mds_diags_support) + phba->hbqs[LPFC_ELS_HBQ].entry_count = + lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count >> 1; + else + phba->hbqs[LPFC_ELS_HBQ].entry_count = + lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count; phba->hbq_count = 1; lpfc_sli_hbqbuf_init_hbqs(phba, LPFC_ELS_HBQ); /* Initially populate or replenish the HBQs */ @@ -4961,7 +5228,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) LPFC_SLI3_CRP_ENABLED | LPFC_SLI3_DSS_ENABLED); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0442 Adapter failed to init, mbxCmd x%x " "CONFIG_PORT, mbxStatus x%x Data: x%x\n", pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0); @@ -4999,23 +5266,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) } else phba->max_vpi = 0; - phba->fips_level = 0; - phba->fips_spec_rev = 0; - if (pmb->u.mb.un.varCfgPort.gdss) { - phba->sli3_options |= LPFC_SLI3_DSS_ENABLED; - phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level; - phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2850 Security Crypto Active. FIPS x%d " - "(Spec Rev: x%d)", - phba->fips_level, phba->fips_spec_rev); - } - if (pmb->u.mb.un.varCfgPort.sec_err) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2856 Config Port Security Crypto " - "Error: x%x ", - pmb->u.mb.un.varCfgPort.sec_err); - } if (pmb->u.mb.un.varCfgPort.gerbm) phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; if (pmb->u.mb.un.varCfgPort.gcrp) @@ -5024,11 +5274,17 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; phba->port_gp = phba->mbox->us.s3_pgp.port; + /* + * If the port cannot support the host's requested features + * then turn off the global config parameters to disable the + * feature in the driver. This is not a fatal error. + */ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { if (pmb->u.mb.un.varCfgPort.gbg == 0) { phba->cfg_enable_bg = 0; + phba->cfg_external_dif = 0; phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0443 Adapter did not grant " "BlockGuard\n"); } @@ -5067,7 +5323,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) switch (phba->cfg_sli_mode) { case 2: if (phba->cfg_enable_npiv) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1824 NPIV enabled: Override sli_mode " "parameter (%d) to auto (0).\n", phba->cfg_sli_mode); @@ -5079,7 +5335,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) case 3: break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1819 Unrecognized sli_mode parameter: %d.\n", phba->cfg_sli_mode); @@ -5090,7 +5346,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli_config_port(phba, mode); if (rc && phba->cfg_sli_mode == 3) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1820 Unable to select SLI-3. " "Not supported by adapter.\n"); if (rc && mode != 2) @@ -5125,7 +5381,6 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) } else { phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE; phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE; - phba->sli3_options = 0; } lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -5145,17 +5400,16 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) */ if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) { longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG; - phba->vpi_bmask = kcalloc(longs, - sizeof(unsigned long), + phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (!phba->vpi_bmask) { rc = -ENOMEM; goto lpfc_sli_hba_setup_error; } - phba->vpi_ids = kcalloc(phba->max_vpi + 1, - sizeof(uint16_t), - GFP_KERNEL); + phba->vpi_ids = kzalloc( + (phba->max_vpi+1) * sizeof(uint16_t), + GFP_KERNEL); if (!phba->vpi_ids) { kfree(phba->vpi_bmask); rc = -ENOMEM; @@ -5184,7 +5438,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) lpfc_sli_hba_setup_error: phba->link_state = LPFC_HBA_ERROR; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0445 Firmware initialization failed\n"); return rc; } @@ -5381,7 +5635,7 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3084 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, reqlen); @@ -5412,21 +5666,27 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) bf_get(lpfc_cntl_attr_lnk_type, cntl_attr); phba->sli4_hba.lnk_info.lnk_no = bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr); + phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); + phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, sizeof(phba->BIOSVersion)); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s\n", + "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " + "flash_id: x%02x, asic_rev: x%02x\n", phba->sli4_hba.lnk_info.lnk_tp, phba->sli4_hba.lnk_info.lnk_no, - phba->BIOSVersion); + phba->BIOSVersion, phba->sli4_hba.flash_id, + phba->sli4_hba.asic_rev); out_free_mboxq: - if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - else - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) { + if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + else + mempool_free(mboxq, phba->mbox_mem_pool); + } return rc; } @@ -5527,10 +5787,12 @@ retrieve_ppname: } out_free_mboxq: - if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - else - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) { + if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + else + mempool_free(mboxq, phba->mbox_mem_pool); + } return rc; } @@ -5553,7 +5815,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM); if (sli4_hba->nvmels_cq) sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0, - LPFC_QUEUE_REARM); + LPFC_QUEUE_REARM); if (sli4_hba->hdwq) { /* Loop thru all Hardware Queues */ @@ -5637,7 +5899,7 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, rsrc_info = &mbox->u.mqe.un.rsrc_extent_info; if (bf_get(lpfc_mbox_hdr_status, &rsrc_info->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2930 Failed to get resource extents " "Status 0x%x Add'l Status 0x%x\n", bf_get(lpfc_mbox_hdr_status, @@ -5775,7 +6037,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt, LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT, req_len, *emb); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2982 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -5831,7 +6093,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) return -EIO; if ((rsrc_cnt == 0) || (rsrc_size == 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3009 No available Resource Extents " "for resource type 0x%x: Count: 0x%x, " "Size 0x%x\n", type, rsrc_cnt, @@ -5880,14 +6142,14 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) length = sizeof(struct lpfc_rsrc_blks); switch (type) { case LPFC_RSC_TYPE_FCOE_RPI: - phba->sli4_hba.rpi_bmask = kcalloc(longs, + phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.rpi_ids = kcalloc(rsrc_id_cnt, + phba->sli4_hba.rpi_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_ids)) { @@ -5909,13 +6171,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; break; case LPFC_RSC_TYPE_FCOE_VPI: - phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long), + phba->vpi_bmask = kzalloc(longs * + sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->vpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->vpi_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t), + phba->vpi_ids = kzalloc(rsrc_id_cnt * + sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->vpi_ids)) { kfree(phba->vpi_bmask); @@ -5929,7 +6193,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->lpfc_vpi_blk_list; break; case LPFC_RSC_TYPE_FCOE_XRI: - phba->sli4_hba.xri_bmask = kcalloc(longs, + phba->sli4_hba.xri_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_bmask)) { @@ -5937,7 +6201,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) goto err_exit; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_ids = kcalloc(rsrc_id_cnt, + phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_ids)) { @@ -5952,14 +6216,14 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; break; case LPFC_RSC_TYPE_FCOE_VFI: - phba->sli4_hba.vfi_bmask = kcalloc(longs, + phba->sli4_hba.vfi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.vfi_ids = kcalloc(rsrc_id_cnt, + phba->sli4_hba.vfi_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_ids)) { @@ -6082,7 +6346,7 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents; if (bf_get(lpfc_mbox_hdr_status, &dealloc_rsrc->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2919 Failed to release resource extents " "for type %d - Status 0x%x Add'l Status 0x%x. " "Resource memory not released.\n", @@ -6146,11 +6410,12 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) return rc; } -static void +void lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, uint32_t feature) { uint32_t len; + u32 sig_freq = 0; len = sizeof(struct lpfc_mbx_set_feature) - sizeof(struct lpfc_sli4_cfg_mhdr); @@ -6173,8 +6438,61 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS; mbox->u.mqe.un.set_feature.param_len = 8; break; - } + case LPFC_SET_CGN_SIGNAL: + if (phba->cmf_active_mode == LPFC_CFG_OFF) + sig_freq = 0; + else + sig_freq = phba->cgn_sig_freq; + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_BOTH) { + bf_set(lpfc_mbx_set_feature_CGN_alarm_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + bf_set(lpfc_mbx_set_feature_CGN_warn_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + } + + if (phba->cgn_reg_signal == LPFC_CGN_SIGNAL_WARN) + bf_set(lpfc_mbx_set_feature_CGN_warn_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + + if (phba->cmf_active_mode == LPFC_CFG_OFF || + phba->cgn_reg_signal == LPFC_CGN_SIGNAL_NO_SPT) + sig_freq = 0; + else + sig_freq = lpfc_acqe_cgn_frequency; + + bf_set(lpfc_mbx_set_feature_CGN_acqe_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + + mbox->u.mqe.un.set_feature.feature = LPFC_SET_CGN_SIGNAL; + mbox->u.mqe.un.set_feature.param_len = 12; + break; + case LPFC_SET_DUAL_DUMP: + bf_set(lpfc_mbx_set_feature_dd, + &mbox->u.mqe.un.set_feature, LPFC_ENABLE_DUAL_DUMP); + bf_set(lpfc_mbx_set_feature_ddquery, + &mbox->u.mqe.un.set_feature, 0); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_DUAL_DUMP; + mbox->u.mqe.un.set_feature.param_len = 4; + break; + case LPFC_SET_ENABLE_E2E: + mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_E2E; + mbox->u.mqe.un.set_feature.param_len = 4; + bf_set(lpfc_mbx_set_feature_e2elunq, + &mbox->u.mqe.un.set_feature, + phba->pport->cfg_lun_queue_depth); + bf_set(lpfc_mbx_set_feature_e2e, + &mbox->u.mqe.un.set_feature, + phba->sli4_hba.pc_sli4_params.E2E_attr); + break; + case LPFC_SET_ENABLE_CMF: + bf_set(lpfc_mbx_set_feature_dd, &mbox->u.mqe.un.set_feature, 1); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_CMF; + mbox->u.mqe.un.set_feature.param_len = 4; + bf_set(lpfc_mbx_set_feature_cmf, + &mbox->u.mqe.un.set_feature, 1); + break; + } return; } @@ -6190,11 +6508,16 @@ lpfc_ras_stop_fwlog(struct lpfc_hba *phba) { struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; - ras_fwlog->ras_active = false; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); /* Disable FW logging to host memory */ writel(LPFC_CTL_PDEV_CTL_DDL_RAS, phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); + + /* Wait 10 milli Sec Fimware need to stop using DMA buffer */ + msleep(10); } /** @@ -6230,7 +6553,9 @@ lpfc_sli4_ras_dma_free(struct lpfc_hba *phba) ras_fwlog->lwpd.virt = NULL; } - ras_fwlog->ras_active = false; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); } /** @@ -6261,7 +6586,7 @@ lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, &ras_fwlog->lwpd.phys, GFP_KERNEL); if (!ras_fwlog->lwpd.virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6185 LWPD Memory Alloc Failed\n"); return -ENOMEM; @@ -6280,7 +6605,8 @@ lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, LPFC_RAS_MAX_ENTRY_SIZE, - &dmabuf->phys, GFP_KERNEL); + &dmabuf->phys, + GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); rc = -ENOMEM; @@ -6322,7 +6648,7 @@ lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (mb->mbxStatus != MBX_SUCCESS || shdr_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6188 FW LOG mailbox " "completed with status x%x add_status x%x," " mbx status x%x\n", @@ -6332,7 +6658,9 @@ lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto disable_ras; } - ras_fwlog->ras_active = true; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = ACTIVE; + spin_unlock_irq(&phba->hbalock); mempool_free(pmb, phba->mbox_mem_pool); return; @@ -6364,6 +6692,10 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, uint32_t len = 0, fwlog_buffsize, fwlog_entry_count; int rc = 0; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); + fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize); fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE); @@ -6384,7 +6716,7 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, /* Setup Mailbox command */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6190 RAS MBX Alloc Failed"); rc = -ENOMEM; goto mem_free; @@ -6423,13 +6755,16 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys); mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys); + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = REG_INPROGRESS; + spin_unlock_irq(&phba->hbalock); mbox->vport = phba->pport; mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6191 FW-Log Mailbox failed. " "status %d mbxStatus : x%x", rc, bf_get(lpfc_mqe_status, &mbox->u.mqe)); @@ -6565,7 +6900,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* RPIs. */ count = phba->sli4_hba.max_cfg_param.max_rpi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3279 Invalid provisioning of " "rpi:%d\n", count); rc = -EINVAL; @@ -6573,14 +6908,15 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.rpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.rpi_bmask = kcalloc(longs, + phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.rpi_ids = kcalloc(count, sizeof(uint16_t), + phba->sli4_hba.rpi_ids = kzalloc(count * + sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_ids)) { rc = -ENOMEM; @@ -6593,7 +6929,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VPIs. */ count = phba->sli4_hba.max_cfg_param.max_vpi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3280 Invalid provisioning of " "vpi:%d\n", count); rc = -EINVAL; @@ -6601,13 +6937,15 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.vpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long), + phba->vpi_bmask = kzalloc(longs * + sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->vpi_bmask)) { rc = -ENOMEM; goto free_rpi_ids; } - phba->vpi_ids = kcalloc(count, sizeof(uint16_t), + phba->vpi_ids = kzalloc(count * + sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->vpi_ids)) { rc = -ENOMEM; @@ -6620,7 +6958,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* XRIs. */ count = phba->sli4_hba.max_cfg_param.max_xri; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3281 Invalid provisioning of " "xri:%d\n", count); rc = -EINVAL; @@ -6628,7 +6966,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.xri_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.xri_bmask = kcalloc(longs, + phba->sli4_hba.xri_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_bmask)) { @@ -6636,7 +6974,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) goto free_vpi_ids; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_ids = kcalloc(count, sizeof(uint16_t), + phba->sli4_hba.xri_ids = kzalloc(count * + sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_ids)) { rc = -ENOMEM; @@ -6649,7 +6988,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VFIs. */ count = phba->sli4_hba.max_cfg_param.max_vfi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3282 Invalid provisioning of " "vfi:%d\n", count); rc = -EINVAL; @@ -6657,14 +6996,15 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.vfi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.vfi_bmask = kcalloc(longs, + phba->sli4_hba.vfi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_bmask)) { rc = -ENOMEM; goto free_xri_ids; } - phba->sli4_hba.vfi_ids = kcalloc(count, sizeof(uint16_t), + phba->sli4_hba.vfi_ids = kzalloc(count * + sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_ids)) { rc = -ENOMEM; @@ -6827,7 +7167,7 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT, req_len, emb); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2983 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -6870,7 +7210,7 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, } if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2984 Failed to read allocated resources " "for type %d - Status 0x%x Add'l Status 0x%x.\n", type, @@ -6885,7 +7225,7 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, } /** - * lpfc_sli4_repost_sgl_list - Repost the buffers sgl pages as block + * lpfc_sli4_repost_sgl_list - Repsot the buffers sgl pages as block * @phba: pointer to lpfc hba data structure. * @pring: Pointer to driver SLI ring object. * @sgl_list: linked link of sgl buffers to post @@ -7025,7 +7365,7 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba, spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irq(&phba->hbalock); } else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3161 Failure to post sgl to port.\n"); return -EIO; } @@ -7080,7 +7420,7 @@ lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION; mbox->u.mqe.un.set_host_data.param_len = LPFC_HOST_OS_DRIVER_VERSION_SIZE; - snprintf(mbox->u.mqe.un.set_host_data.data, + snprintf(mbox->u.mqe.un.set_host_data.un.data, LPFC_HOST_OS_DRIVER_VERSION_SIZE, "Linux %s v"LPFC_DRIVER_VERSION, (phba->hba_flag & HBA_FCOE_MODE) ? "FCoE" : "FC"); @@ -7128,7 +7468,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys); rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe); if (rc < 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6421 Cannot post to HRQ %d: %x %x %x " "DRQ %x %x\n", hrq->queue_id, @@ -7148,6 +7488,407 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, return 1; } +static void lpfc_sli4_dip(struct lpfc_hba *phba) +{ + uint32_t if_type; + + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2 || + if_type == LPFC_SLI_INTF_IF_TYPE_6) { + struct lpfc_register reg_data; + + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + ®_data.word0)) + return; + + if (bf_get(lpfc_sliport_status_dip, ®_data)) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2904 Firmware Dump Image Present" + " on Adapter"); + } +} + +static void +lpfc_mbx_cmpl_cgn_set_ftrs(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + union lpfc_sli4_cfg_shdr *shdr; + u32 shdr_status, shdr_add_status; + u32 sig, acqe; + + /* Two outcomes. (1) Set featurs was successul and EDC negotiation + * is done. (2) Mailbox failed and send FPIN support only. + */ + shdr = (union lpfc_sli4_cfg_shdr *) + &pmb->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || pmb->u.mb.mbxStatus) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "2516 CGN SET_FEATURE mbox failed with " + "status x%x add_status x%x, mbx status x%x " + "Reset Congestion to FPINs only\n", + shdr_status, shdr_add_status, + pmb->u.mb.mbxStatus); + /* If there is a mbox error, move on to RDF */ + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + goto out; + } + + /* Zero out Congestion Signal ACQE counter */ + phba->cgn_acqe_cnt = 0; + + acqe = bf_get(lpfc_mbx_set_feature_CGN_acqe_freq, + &pmb->u.mqe.un.set_feature); + sig = bf_get(lpfc_mbx_set_feature_CGN_warn_freq, + &pmb->u.mqe.un.set_feature); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4620 SET_FEATURES Success: Freq: %ds %dms " + " Reg: x%x x%x\n", acqe, sig, + phba->cgn_reg_signal, phba->cgn_reg_fpin); +out: + mempool_free(pmb, phba->mbox_mem_pool); + + /* Register for FPIN events from the fabric now that the + * EDC common_set_features has completed. + */ + lpfc_issue_els_rdf(vport, 0); +} + +int +lpfc_config_cgn_signal(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + u32 rc; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + lpfc_set_features(phba, mboxq, LPFC_SET_CGN_SIGNAL); + mboxq->vport = phba->pport; + mboxq->mbox_cmpl = lpfc_mbx_cmpl_cgn_set_ftrs; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4621 SET_FEATURES: FREQ sig x%x acqe x%x: " + "Reg: x%x x%x\n", + phba->cgn_sig_freq, lpfc_acqe_cgn_frequency, + phba->cgn_reg_signal, phba->cgn_reg_fpin); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) + goto out; + return 0; + + out: + mempool_free(mboxq, phba->mbox_mem_pool); + + /* If there is a mbox error, move on to RDF */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = LPFC_CGN_SIGNAL_NO_SPT; + lpfc_issue_els_rdf(phba->pport, 0); + return -EIO; +} + +/** + * lpfc_init_idle_stat_hb - Initialize idle_stat tracking + * + * This routine initializes the per-cq idle_stat to dynamically dictate + * polling decisions. + * + * Note: NVMET and CGN mgmt modes are not supported. + * + * Return codes: + * None + **/ +static void lpfc_init_idle_stat_hb(struct lpfc_hba *phba) +{ + int i; + struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_queue *cq; + struct lpfc_idle_stat *idle_stat; + u64 wall; + + for_each_present_cpu(i) { + hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq]; + cq = hdwq->io_cq; + + /* Skip if we've already handled this cq's primary CPU */ + if (cq->chann != i) + continue; + + idle_stat = &phba->sli4_hba.idle_stat[i]; + + idle_stat->prev_idle = get_cpu_idle_time(i, &wall, 1); + idle_stat->prev_wall = wall; + + if (phba->nvmet_support || + phba->cmf_active_mode != LPFC_CFG_OFF) + cq->poll_mode = LPFC_QUEUE_WORK; + else + cq->poll_mode = LPFC_IRQ_POLL; + } + + if (!phba->nvmet_support) + schedule_delayed_work(&phba->idle_stat_delay_work, + msecs_to_jiffies(LPFC_IDLE_STAT_DELAY)); +} + +/** + * lpfc_cmf_setup - Initialize idle_stat tracking + * @phba: Pointer to HBA context object. + * + * This is called from HBA setup during driver load or when the HBA + * comes online. this does all the initialization to support CMF and E2E. + **/ +static int +lpfc_cmf_setup(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_mqe *mqe; + struct lpfc_dmabuf *mp; + struct lpfc_pc_sli4_params *sli4_params; + struct lpfc_sli4_parameters *mbx_sli4_parameters; + int length; + int rc, cmf, e2e_ver; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + mqe = &mboxq->u.mqe; + + /* Read the port's SLI4 Config Parameters */ + length = (sizeof(struct lpfc_mbx_get_sli4_parameters) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS, + length, LPFC_SLI4_MBX_EMBED); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (unlikely(rc)) { + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; + } + + /* Gather info on CMF and E2E support */ + sli4_params = &phba->sli4_hba.pc_sli4_params; + mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters; + sli4_params->E2E_attr = bf_get(cfg_e2em_attr_value, + mbx_sli4_parameters); + sli4_params->cmf = bf_get(cfg_cmf, mbx_sli4_parameters); + + /* Are we forcing E2E off via module parameter? */ + if (!phba->cfg_enable_e2e) + sli4_params->E2E_attr = 0; + + /* Always try to enable E2E feature if we can */ + if (sli4_params->E2E_attr) { + lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_E2E); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + e2e_ver = bf_get(lpfc_mbx_set_feature_e2e, + &mboxq->u.mqe.un.set_feature); + + if (rc == MBX_SUCCESS) { + if (e2e_ver) { + lpfc_printf_log(phba, + KERN_WARNING, LOG_CGN_MGMT, + "6215 E2E is enabled\n"); + sli4_params->E2E_attr = e2e_ver; + } else { + lpfc_printf_log(phba, + KERN_WARNING, LOG_CGN_MGMT, + "6338 E2E is disabled\n"); + sli4_params->E2E_attr = 0; + } + } else { + /* E2E_attr is already set from GET_SLI4_PARAMETERS */ + lpfc_printf_log(phba, KERN_INFO, + LOG_CGN_MGMT | LOG_INIT, + "6216 Enable E2E Mailbox x%x (x%x/x%x) " + "failed, rc:x%x e2e:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get + (phba, mboxq), + lpfc_sli_config_mbox_opcode_get + (phba, mboxq), + rc, sli4_params->E2E_attr); + } + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6217 E2E is disabled\n"); + } + + /* Ensure FDMI is enabled for E2E if enable_e2e is set */ + if (sli4_params->E2E_attr) + phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT; + + /* Always try to enable CMF feature if we can */ + if (sli4_params->cmf) { + lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_CMF); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + cmf = bf_get(lpfc_mbx_set_feature_cmf, + &mboxq->u.mqe.un.set_feature); + if (rc == MBX_SUCCESS && cmf) { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6218 CMF is enabled: mode %d\n", + phba->cmf_active_mode); + } else { + lpfc_printf_log(phba, KERN_WARNING, + LOG_CGN_MGMT | LOG_INIT, + "6219 Enable CMF Mailbox x%x (x%x/x%x) " + "failed, rc:x%x dd:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get + (phba, mboxq), + lpfc_sli_config_mbox_opcode_get + (phba, mboxq), + rc, cmf); + sli4_params->cmf = 0; + phba->cmf_active_mode = LPFC_CFG_OFF; + goto no_cmf; + } + + /* Allocate Congestion Information Buffer */ + if (!phba->cgn_i) { + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (mp) + mp->virt = dma_alloc_coherent + (&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + &mp->phys, GFP_KERNEL); + if (!mp || !mp->virt) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2640 Failed to alloc memory " + "for Congestion Info\n"); + kfree(mp); + sli4_params->cmf = 0; + phba->cmf_active_mode = LPFC_CFG_OFF; + goto no_cmf; + } + phba->cgn_i = mp; + + /* initialize congestion buffer info */ + lpfc_init_congestion_buf(phba); + lpfc_init_congestion_stat(phba); + } + + rc = lpfc_sli4_cgn_params_read(phba); + if (rc < 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "6242 Error reading Cgn Params (%d)\n", + rc); + /* Ensure CGN Mode is off */ + sli4_params->cmf = 0; + } else if (!rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "6243 CGN Event empty object.\n"); + /* Ensure CGN Mode is off */ + sli4_params->cmf = 0; + } + } else { +no_cmf: + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6220 CMF is disabled\n"); + } + + /* Only register congestion buffer with firmware if BOTH + * CMF and E2E are enabled. + */ + if (sli4_params->cmf && sli4_params->E2E_attr) { + rc = lpfc_reg_congestion_buf(phba); + if (rc) { + dma_free_coherent(&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + phba->cgn_i->virt, phba->cgn_i->phys); + kfree(phba->cgn_i); + phba->cgn_i = NULL; + /* Ensure CGN Mode is off */ + phba->cmf_active_mode = LPFC_CFG_OFF; + return 0; + } + } + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "6470 Setup E2Eattr %d CMF %d mode %d\n", + sli4_params->E2E_attr, sli4_params->cmf, + phba->cmf_active_mode); + + mempool_free(mboxq, phba->mbox_mem_pool); + + /* Initialize atomic counters */ + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + atomic_set(&phba->cgn_driver_evt_cnt, 0); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + + phba->cmf_interval_rate = LPFC_CMF_INTERVAL; + + /* Allocate RX Monitor Buffer */ + if (!phba->rxtable) { + phba->rxtable = kmalloc(LPFC_MAX_RXMONITOR_ENTRY * + sizeof(struct rxtable_entry), + GFP_KERNEL); + if (!phba->rxtable) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2644 Failed to alloc memory " + "for RX Monitor Buffer\n"); + return -ENOMEM; + } + } + atomic_set(&phba->rxtable_idx_head, 0); + atomic_set(&phba->rxtable_idx_tail, 0); + return 0; +} + +static int +lpfc_set_host_tm(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + uint32_t len, rc; + struct timespec64 cur_time; + struct tm broken; + uint32_t month, day, year; + uint32_t hour, minute, second; + struct lpfc_mbx_set_host_date_time *tm; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + len = sizeof(struct lpfc_mbx_set_host_data) - + sizeof(struct lpfc_sli4_cfg_mhdr); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_SET_HOST_DATA, len, + LPFC_SLI4_MBX_EMBED); + + mboxq->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_DATE_TIME; + mboxq->u.mqe.un.set_host_data.param_len = + sizeof(struct lpfc_mbx_set_host_date_time); + tm = &mboxq->u.mqe.un.set_host_data.un.tm; + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + month = broken.tm_mon + 1; + day = broken.tm_mday; + year = broken.tm_year - 100; + hour = broken.tm_hour; + minute = broken.tm_min; + second = broken.tm_sec; + bf_set(lpfc_mbx_set_host_month, tm, month); + bf_set(lpfc_mbx_set_host_day, tm, day); + bf_set(lpfc_mbx_set_host_year, tm, year); + bf_set(lpfc_mbx_set_host_hour, tm, hour); + bf_set(lpfc_mbx_set_host_min, tm, minute); + bf_set(lpfc_mbx_set_host_sec, tm, second); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; +} + /** * lpfc_sli4_hba_setup - SLI4 device initialization PCI function * @phba: Pointer to HBA context object. @@ -7160,7 +7901,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, int lpfc_sli4_hba_setup(struct lpfc_hba *phba) { - int rc, i, cnt, len; + int rc, i, cnt, len, dd; LPFC_MBOXQ_t *mboxq; struct lpfc_mqe *mqe; uint8_t *vpd; @@ -7170,6 +7911,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; struct lpfc_dmabuf *mp; struct lpfc_rqb *rqbp; + u32 flg; /* Perform a PCI function reset to start from clean */ rc = lpfc_pci_function_reset(phba); @@ -7183,9 +7925,21 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else { spin_lock_irq(&phba->hbalock); phba->sli.sli_flag |= LPFC_SLI_ACTIVE; + flg = phba->sli.sli_flag; spin_unlock_irq(&phba->hbalock); + /* Allow a little time after setting SLI_ACTIVE for any polled + * MBX commands to complete via BSG. + */ + for (i = 0; i < 50 && (flg & LPFC_SLI_MBOX_ACTIVE); i++) { + msleep(20); + spin_lock_irq(&phba->hbalock); + flg = phba->sli.sli_flag; + spin_unlock_irq(&phba->hbalock); + } } + lpfc_sli4_dip(phba); + /* * Allocate a single mailbox container for initializing the * port. @@ -7213,6 +7967,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) { phba->hba_flag |= HBA_FCOE_MODE; phba->fcp_embed_io = 0; /* SLI4 FC support only */ +#ifndef BUILD_BRCMFCOE + phba->cfg_enable_auth = LPFC_AUTH_DISABLE; /* SLI4 FC only */ +#endif } else { phba->hba_flag &= ~HBA_FCOE_MODE; } @@ -7226,7 +7983,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->hba_flag &= ~HBA_IOQ_FLUSH; if (phba->sli_rev != LPFC_SLI_REV4) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0376 READ_REV Error. SLI Level %d " "FCoE enabled %d\n", phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE); @@ -7235,6 +7992,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_mbox; } + rc = lpfc_set_host_tm(phba); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT, + "6468 Set host date / time: Status x%x:\n", rc); + /* * Continue initialization with default values even if driver failed * to read FCoE param config regions, only read parameters if the @@ -7268,7 +8029,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) */ rc = lpfc_parse_vpd(phba, vpd, vpd_size); if (unlikely(!rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0377 Error %d parsing vpd. " "Using defaults.\n", rc); rc = 0; @@ -7314,15 +8075,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3362 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, rc); - phba->pport->cfg_lun_queue_depth = rc; - } - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_0) { lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY); @@ -7385,6 +8137,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) { phba->cfg_enable_bg = 0; + phba->cfg_external_dif = 0; phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; ftr_rsp++; } @@ -7400,8 +8153,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "x%x x%x x%x\n", mqe->un.req_ftrs.word2, mqe->un.req_ftrs.word3, phba->cfg_enable_bg, phba->cfg_enable_npiv, phba->max_vpi); - if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) - phba->cfg_enable_bg = 0; + if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs))) phba->cfg_enable_npiv = 0; } @@ -7411,13 +8163,30 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED); spin_unlock_irq(&phba->hbalock); + /* Always try to enable dual dump feature if we can */ + lpfc_set_features(phba, mboxq, LPFC_SET_DUAL_DUMP); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + dd = bf_get(lpfc_mbx_set_feature_dd, &mboxq->u.mqe.un.set_feature); + if ((rc == MBX_SUCCESS) && (dd == LPFC_ENABLE_DUAL_DUMP)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "6448 Dual Dump is enabled\n"); + else + lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_INIT, + "6447 Dual Dump Mailbox x%x (x%x/x%x) failed, " + "rc:x%x dd:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get( + phba, mboxq), + lpfc_sli_config_mbox_opcode_get( + phba, mboxq), + rc, dd); /* * Allocate all resources (xri,rpi,vpi,vfi) now. Subsequent * calls depends on these resources to complete port setup. */ rc = lpfc_sli4_alloc_resource_identifiers(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2920 Failed to alloc Resource IDs " "rc = x%x\n", rc); goto out_free_mbox; @@ -7428,8 +8197,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "2134 Failed to set host os driver version %x", - rc); + "2134 Failed to set host os driver " + "version %x ", rc); } /* Read the port's service parameters. */ @@ -7456,7 +8225,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) kfree(mp); mboxq->ctx_buf = NULL; if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0382 READ_SPARAM command failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, mqe)); @@ -7474,7 +8243,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Create all the SLI4 queues */ rc = lpfc_sli4_queue_create(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3089 Failed to allocate queues\n"); rc = -ENODEV; goto out_free_mbox; @@ -7482,7 +8251,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Set up all the queues to the device */ rc = lpfc_sli4_queue_setup(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0381 Error %d during queue setup.\n ", rc); goto out_stop_timers; } @@ -7493,7 +8262,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* update host els xri-sgl sizes and mappings */ rc = lpfc_sli4_els_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1400 Failed to update xri-sgl size and " "mapping: %d\n", rc); goto out_destroy_queue; @@ -7503,7 +8272,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli4_repost_sgl_list(phba, &phba->sli4_hba.lpfc_els_sgl_list, phba->sli4_hba.els_xri_cnt); if (unlikely(rc < 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0582 Error %d during els sgl post " "operation\n", rc); rc = -ENODEV; @@ -7515,7 +8284,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* update host nvmet xri-sgl sizes and mappings */ rc = lpfc_sli4_nvmet_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6308 Failed to update nvmet-sgl size " "and mapping: %d\n", rc); goto out_destroy_queue; @@ -7527,7 +8296,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_nvmet_sgl_list, phba->sli4_hba.nvmet_xri_cnt); if (unlikely(rc < 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3117 Error %d during nvmet " "sgl post\n", rc); rc = -ENODEV; @@ -7535,14 +8304,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } phba->sli4_hba.nvmet_xri_cnt = rc; - cnt = phba->cfg_iocb_cnt * 1024; - /* We need 1 iocbq for every SGL, for IO processing */ - cnt += phba->sli4_hba.nvmet_xri_cnt; + /* We allocate an iocbq for every receive context SGL. + * The additional allocation is for abort and ls handling. + */ + cnt = phba->sli4_hba.nvmet_xri_cnt + + phba->sli4_hba.max_cfg_param.max_xri; } else { /* update host common xri-sgl sizes and mappings */ rc = lpfc_sli4_io_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6082 Failed to update nvme-sgl size " "and mapping: %d\n", rc); goto out_destroy_queue; @@ -7551,7 +8322,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* register the allocated common sgl pool to the port */ rc = lpfc_sli4_repost_io_sgl_list(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6116 Error %d during nvme sgl post " "operation\n", rc); /* Some NVME buffers were moved to abort nvme list */ @@ -7559,17 +8330,20 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_destroy_queue; } - cnt = phba->cfg_iocb_cnt * 1024; + /* Each lpfc_io_buf job structure has an iocbq element. + * This cnt provides for abort, els, ct and ls requests. + */ + cnt = phba->sli4_hba.max_cfg_param.max_xri; } if (!phba->sli.iocbq_lookup) { /* Initialize and populate the iocb list per host */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2821 initialize iocb list %d total %d\n", - phba->cfg_iocb_cnt, cnt); + "2821 initialize iocb list with %d entries\n", + cnt); rc = lpfc_init_iocb_list(phba, cnt); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1413 Failed to init iocb list.\n"); goto out_destroy_queue; } @@ -7598,7 +8372,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Post the rpi header region to the device. */ rc = lpfc_sli4_post_all_rpi_hdrs(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0393 Error %d during rpi post operation\n", rc); rc = -ENODEV; @@ -7646,7 +8420,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Don't post more new bufs if repost already recovered * the nvme sgls. - */ + **/ if (phba->nvmet_support == 0) { if (phba->sli4_hba.io_xri_cnt == 0) { len = lpfc_new_io_buf( @@ -7682,7 +8456,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start heart beat timer */ mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); phba->last_completion_time = jiffies; /* start eq_delay heartbeat */ @@ -7690,6 +8464,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) queue_delayed_work(phba->wq, &phba->eq_delay_work, msecs_to_jiffies(LPFC_EQ_DELAY_MSECS)); + /* start per phba idle_stat_delay heartbeat */ + lpfc_init_idle_stat_hb(phba); + /* Start error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); @@ -7737,14 +8514,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Indicate device interrupt mode */ phba->sli4_hba.intr_enable = 1; + /* Setup CMF after HBA is initialized */ + lpfc_cmf_setup(phba); + if (!(phba->hba_flag & HBA_FCOE_MODE) && (phba->hba_flag & LINK_DISABLED)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3103 Adapter Link is disabled.\n"); lpfc_down_link(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3104 Adapter failed to issue " "DOWN_LINK mbox cmd, rc:x%x\n", rc); goto out_io_buff_free; @@ -7752,12 +8532,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { /* don't perform init_link on SLI4 FC port loopback test */ if (!(phba->link_flag & LS_LOOPBACK_MODE)) { - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + rc = phba->lpfc_hba_init_link(phba); if (rc) goto out_io_buff_free; } } mempool_free(mboxq, phba->mbox_mem_pool); + +#ifndef BUILD_BRCMFCOE + lpfc_auth_read_cfg_object(phba); +#endif + phba->hba_flag |= HBA_SETUP; return rc; out_io_buff_free: /* Free allocated IO Buffers */ @@ -7788,9 +8573,17 @@ out_free_mbox: * done by the worker thread function lpfc_mbox_timeout_handler. **/ void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +lpfc_mbox_timeout(unsigned long ptr) +#else lpfc_mbox_timeout(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_hba *phba = (struct lpfc_hba *) ptr; +#else struct lpfc_hba *phba = from_timer(phba, t, sli.mbox_tmo); +#endif unsigned long iflag; uint32_t tmo_posted; @@ -7878,7 +8671,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) if (sli4_hba->hdwq) { for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) { eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq; - if (eq && eq->queue_id == sli4_hba->mbx_cq->assoc_qid) { + if (eq->queue_id == sli4_hba->mbx_cq->assoc_qid) { fpeq = eq; break; } @@ -7929,8 +8722,10 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; - /* If the mailbox completed, process the completion and return */ - if (lpfc_sli4_process_missed_mbox_completions(phba)) + /* If the mailbox completed, process the completion */ + lpfc_sli4_process_missed_mbox_completions(phba); + + if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) return; if (pmbox != NULL) @@ -7951,7 +8746,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) } /* Mbox cmd timeout */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0310 Mailbox command x%x timeout Data: x%x x%x x%px\n", mb->mbxCommand, phba->pport->port_state, @@ -7971,9 +8766,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); - lpfc_sli_abort_fcp_rings(phba); - - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0345 Resetting board due to mailbox timeout\n"); /* Reset the HBA device */ @@ -8071,7 +8864,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0311 Mailbox command x%x cannot " "issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8083,7 +8876,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, if (lpfc_readl(phba->HCregaddr, &hc_copy) || !(hc_copy & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2528 Mailbox command x%x cannot " "issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8102,7 +8895,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2529 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8114,7 +8907,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2530 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8167,7 +8960,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2531 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8250,7 +9043,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, word */ to_slim = phba->MBslimaddr + sizeof (uint32_t); lpfc_memcpy_to_slim(to_slim, &mbx->un.varWords[0], - MAILBOX_CMD_SIZE - sizeof (uint32_t)); + MAILBOX_CMD_SIZE - sizeof(uint32_t)); /* Next copy over first word, with mbxOwner set */ ldata = *((uint32_t *)mbx); @@ -8415,8 +9208,11 @@ static int lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; + LPFC_MBOXQ_t *mboxq; int rc = 0; unsigned long timeout = 0; + u32 sli_flag; + u8 cmd, subsys, opcode; /* Mark the asynchronous mailbox command posting as blocked */ spin_lock_irq(&phba->hbalock); @@ -8434,12 +9230,37 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) if (timeout) lpfc_sli4_process_missed_mbox_completions(phba); - /* Wait for the outstnading mailbox command to complete */ + /* Wait for the outstanding mailbox command to complete */ while (phba->sli.mbox_active) { /* Check active mailbox complete status every 2ms */ msleep(2); if (time_after(jiffies, timeout)) { - /* Timeout, marked the outstanding cmd not complete */ + /* Timeout, mark the outstanding cmd not complete */ + + /* Sanity check sli.mbox_active has not completed or + * cancelled from another context during last 2ms sleep, + * so take hbalock to be sure before logging. + */ + spin_lock_irq(&phba->hbalock); + if (phba->sli.mbox_active) { + mboxq = phba->sli.mbox_active; + cmd = mboxq->u.mb.mbxCommand; + subsys = lpfc_sli_config_mbox_subsys_get(phba, + mboxq); + opcode = lpfc_sli_config_mbox_opcode_get(phba, + mboxq); + sli_flag = psli->sli_flag; + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2352 Mailbox command x%x " + "(x%x/x%x) sli_flag x%x could " + "not complete\n", + cmd, subsys, opcode, + sli_flag); + } else { + spin_unlock_irq(&phba->hbalock); + } + rc = 1; break; } @@ -8558,7 +9379,7 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) spin_lock_irqsave(&phba->hbalock, iflag); if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2532 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8679,7 +9500,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, rc = lpfc_mbox_dev_check(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2544 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8701,7 +9522,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2541 Mailbox command x%x " "(x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, @@ -8735,7 +9556,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2597 Sync Mailbox command " "x%x (x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, @@ -8756,7 +9577,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, /* Now, interrupt mode asynchrous mailbox command */ rc = lpfc_mbox_cmd_check(phba, mboxq); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2543 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8824,7 +9645,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) } if (unlikely(phba->sli.mbox_active)) { spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0384 There is pending active mailbox cmd\n"); return MBX_NOT_FINISHED; } @@ -8885,7 +9706,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) /* Post the mailbox command to the port */ rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2533 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8961,7 +9782,7 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->lpfc_sli_brdready = lpfc_sli_brdready_s4; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1420 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; @@ -8984,7 +9805,6 @@ void __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { - lockdep_assert_held(&phba->hbalock); /* Insert the caller's iocb in the txq tail for later processing. */ list_add_tail(&piocb->list, &pring->txq); } @@ -9012,7 +9832,6 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { struct lpfc_iocbq * nextiocb; - lockdep_assert_held(&phba->hbalock); nextiocb = lpfc_sli_ringtx_get(phba, pring); if (!nextiocb) { @@ -9053,13 +9872,10 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, IOCB_t *iocb; struct lpfc_sli_ring *pring = &phba->sli.sli3_ring[ring_number]; - lockdep_assert_held(&phba->hbalock); - if (piocb->iocb_cmpl && (!piocb->vport) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1807 IOCB x%x failed. No vport\n", piocb->iocb.ulpCommand); dump_stack(); @@ -9299,6 +10115,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, struct lpfc_nodelist *ndlp; uint32_t *pcmd; uint32_t if_type; + struct lpfc_io_buf *lpfc_cmd; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -9313,6 +10130,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, memset(wqe, 0, sizeof(union lpfc_wqe128)); /* Some of the fields are in the right position already */ memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); + /* The ct field has moved so reset */ wqe->generic.wqe_com.word7 = 0; wqe->generic.wqe_com.word10 = 0; @@ -9354,7 +10172,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, else ndlp = (struct lpfc_nodelist *)iocbq->context1; if (!iocbq->iocb.ulpLe) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2007 Only Limited Edition cmd Format" " supported 0x%x\n", iocbq->iocb.ulpCommand); @@ -9385,10 +10203,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_RDF || + *pcmd == ELS_CMD_EDC || *pcmd == ELS_CMD_RSCN_XMT || *pcmd == ELS_CMD_FDISC || *pcmd == ELS_CMD_LOGO || - *pcmd == ELS_CMD_PLOGI)) { + *pcmd == ELS_CMD_PLOGI || + (*pcmd & ELS_CMD_MASK) == ELS_CMD_AUTH || + iocbq->iocb_flag & LPFC_IO_RAW)) { bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, iocbq->vport->fc_myDID); @@ -9456,6 +10278,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0); break; case CMD_FCP_IWRITE64_CR: + lpfc_cmd = iocbq->context1; + + /* The ndlp indicates if first burst support is supported. */ + if (iocbq->iocb_flag & LPFC_IO_LIBDFC) + ndlp = iocbq->context_un.ndlp; + else + ndlp = lpfc_cmd->ndlp; + command_type = FCP_COMMAND_DATA_OUT; /* word3 iocb=iotag wqe=payload_offset_len */ /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ @@ -9463,8 +10293,19 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, xmit_len + sizeof(struct fcp_rsp)); bf_set(cmd_buff_len, &wqe->fcp_iwrite, 0); - /* word4 iocb=parameter wqe=total_xfer_length memcpy */ - /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ + + /* Set first-burst provided it was successfully negotiated */ + if (phba->sli_rev == LPFC_SLI_REV4 && + iocbq->iocb_flag & LPFC_IO_FCP && + !(phba->hba_flag & HBA_FCOE_MODE) && ndlp->first_burst) { + u32 init_len; + + total_len = be32_to_cpu(lpfc_cmd->fcp_cmnd->fcpDl); + init_len = min(total_len, ndlp->first_burst); + wqe->fcp_iwrite.initial_xfer_len = init_len; + wqe->fcp_iwrite.total_xfer_len = total_len; + } + bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpFCP2Rcvy); bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS); @@ -9494,7 +10335,6 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); if (phba->fcp_embed_io) { - struct lpfc_io_buf *lpfc_cmd; struct sli4_sge *sgl; struct fcp_cmnd *fcp_cmnd; uint32_t *ptr; @@ -9532,12 +10372,21 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_erp, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpFCP2Rcvy); bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS); - /* Always open the exchange */ - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); + + /* For a CMF Managed port, iod must be zero'ed */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, + LPFC_WQE_IOD_NONE); + else + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, + LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); + bf_set(wqe_tmo, &wqe->fcp_iread.wqe_com, + iocbq->iocb.ulpTimeout); if (iocbq->iocb_flag & LPFC_IO_OAS) { bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1); bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1); @@ -9601,6 +10450,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, LPFC_WQE_LENLOC_NONE); bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, iocbq->iocb.ulpFCP2Rcvy); + bf_set(wqe_tmo, &wqe->fcp_icmd.wqe_com, + iocbq->iocb.ulpTimeout); if (iocbq->iocb_flag & LPFC_IO_OAS) { bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1); bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1); @@ -9661,7 +10512,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* word6 context tag copied in memcpy */ if (iocbq->iocb.ulpCt_h || iocbq->iocb.ulpCt_l) { ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2015 Invalid CT %x command 0x%x\n", ct, iocbq->iocb.ulpCommand); return IOCB_ERROR; @@ -9840,7 +10691,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, case CMD_FCP_TRSP64_CX: /* Target mode rcv */ case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */ default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2014 Invalid command 0x%x\n", iocbq->iocb.ulpCommand); return IOCB_ERROR; @@ -9862,6 +10713,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_cmnd, &wqe->generic.wqe_com, cmnd); bf_set(wqe_class, &wqe->generic.wqe_com, iocbq->iocb.ulpClass); bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + return 0; } @@ -9875,7 +10727,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue * an iocb command to an HBA with SLI-4 interface spec. * - * This function is called with hbalock held. The function will return success + * This function is called with ringlock held. The function will return success * after it successfully submit the iocb to firmware or after adding to the * txq. **/ @@ -10002,7 +10854,7 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1419 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; @@ -10136,6 +10988,32 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +static void +lpfc_sli_post_recovery_event(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + struct lpfc_work_evt *evtp = &ndlp->recovery_evt; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + + /* Incrementing the reference count until the queued work is done. */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (!evtp->evt_arg1) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + evtp->evt = LPFC_EVT_RECOVER_PORT; + list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + lpfc_worker_wake_up(phba); +} + /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -10226,7 +11104,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, ext_status = axri->parameter & IOERR_PARAM_MASK; if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) - lpfc_sli_abts_recover_port(vport, ndlp); + lpfc_sli_post_recovery_event(phba, ndlp); } /** @@ -10262,13 +11140,13 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; if (evt_code == ASYNC_TEMP_WARN) { temp_event_data.event_code = LPFC_THRESHOLD_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0347 Adapter is very hot, please take " "corrective action. temperature : %d Celsius\n", (uint32_t) icmd->ulpContext); } else { temp_event_data.event_code = LPFC_NORMAL_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0340 Adapter temperature is OK now. " "temperature : %d Celsius\n", (uint32_t) icmd->ulpContext); @@ -10285,7 +11163,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, break; default: iocb_w = (uint32_t *) icmd; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0346 Ring %d handler: unexpected ASYNC_STATUS" " evt_code 0x%x\n" "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" @@ -10461,7 +11339,7 @@ lpfc_sli_setup(struct lpfc_hba *phba) } if (totiocbsize > MAX_SLIM_IOCB_SIZE) { /* Too many cmd / rsp ring entries in SLI2 SLIM */ - printk(KERN_ERR "%d:0462 Too many cmd / rsp ring entries in " + printk(KERN_ERR "%d:0012 Too many cmd / rsp ring entries in " "SLI2 SLIM Data: x%x x%lx\n", phba->brd_no, totiocbsize, (unsigned long) MAX_SLIM_IOCB_SIZE); @@ -10695,14 +11573,14 @@ lpfc_sli_host_down(struct lpfc_vport *vport) set_bit(LPFC_DATA_READY, &phba->data_flags); } prev_pring_flag = pring->flag; - spin_lock_irq(&pring->ring_lock); + spin_lock(&pring->ring_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { if (iocb->vport != vport) continue; list_move_tail(&iocb->list, &completions); } - spin_unlock_irq(&pring->ring_lock); + spin_unlock(&pring->ring_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { if (iocb->vport != vport) @@ -10714,6 +11592,9 @@ lpfc_sli_host_down(struct lpfc_vport *vport) } spin_unlock_irqrestore(&phba->hbalock, flags); + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); @@ -10959,7 +11840,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0402 Cannot find virtual addr for buffer tag on " "ring %d Data x%lx x%px x%px x%x\n", pring->ringno, (unsigned long) tag, @@ -11003,7 +11884,7 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0410 Cannot find virtual addr for mapped buf on " "ring %d Data x%llx x%px x%px x%x\n", pring->ringno, (unsigned long long)phys, @@ -11127,8 +12008,6 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, unsigned long iflags; struct lpfc_nodelist *ndlp; - lockdep_assert_held(&phba->hbalock); - /* * There are certain command types we don't want to abort. And we * don't want to abort commands that are already in the process of @@ -11234,8 +12113,6 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int retval = IOCB_ERROR; IOCB_t *icmd = NULL; - lockdep_assert_held(&phba->hbalock); - /* * There are certain command types we don't want to abort. And we * don't want to abort commands that are already in the process of @@ -11339,7 +12216,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd; int rc = 1; - if (iocbq->vport != vport) + if (!iocbq || iocbq->vport != vport) return rc; if (!(iocbq->iocb_flag & LPFC_IO_FCP) || @@ -11873,7 +12750,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, SLI_IOCB_RET_IOCB); if (retval == IOCB_SUCCESS) { - timeout_req = msecs_to_jiffies(timeout * 1000); + /* make host tmo longer */ + timeout_req = msecs_to_jiffies((timeout + 20) * 1000); timeleft = wait_event_timeout(done_q, lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); @@ -11890,20 +12768,29 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, } spin_unlock_irqrestore(&phba->hbalock, iflags); if (iocb_completed) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0331 IOCB wake signaled\n"); + if ((prspiocbq) && + (prspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY)) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3324 IOCB wake signaled, " + "port timeout the I/O.\n"); + retval = IOCB_ABORTED; + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0331 IOCB wake signaled, " + "port complete the I/O.\n"); + } /* Note: we are not indicating if the IOCB has a success * status or not - that's for the caller to check. * IOCB_SUCCESS means just that the command was sent and * completed. Not that it completed successfully. * */ } else if (timeleft == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0338 IOCB wait timeout error - no " "wake response Data x%x\n", timeout); retval = IOCB_TIMEDOUT; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0330 IOCB wake NOT set, " "Data x%x x%lx\n", timeout, (timeleft / jiffies)); @@ -12165,7 +13052,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) } if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1423 HBA Unrecoverable error: " "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " "ue_mask_lo_reg=0x%x, " @@ -12196,7 +13083,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) readl(phba->sli4_hba.u.if_type2.ERR1regaddr); phba->work_status[1] = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2885 Port Status Event: " "port status reg 0x%x, " "port smphr reg 0x%x, " @@ -12212,7 +13099,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) break; case LPFC_SLI_INTF_IF_TYPE_1: default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2886 HBA Error Attention on unsupported " "if type %d.", if_type); return 1; @@ -12276,7 +13163,7 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba) ha_copy = lpfc_sli4_eratt_read(phba); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0299 Invalid SLI revision (%d)\n", phba->sli_rev); ha_copy = 0; @@ -12509,8 +13396,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) * Stray Mailbox Interrupt, mbxCommand * mbxStatus */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0304 Stray Mailbox " "Interrupt mbxCommand x%x " "mbxStatus x%x\n", @@ -12570,7 +13456,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) if (rc != MBX_BUSY) lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "0350 rc should have" "been MBX_BUSY\n"); if (rc != MBX_NOT_FINISHED) @@ -12585,7 +13471,21 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) spin_unlock_irqrestore( &phba->pport->work_port_lock, iflag); - lpfc_mbox_cmpl_put(phba, pmb); + + /* Do NOT queue MBX_HEARTBEAT to the worker + * thread for processing. + */ + if (pmbox->mbxCommand == MBX_HEARTBEAT) { + /* Process mbox now */ + phba->sli.mbox_active = NULL; + phba->sli.sli_flag &= + ~LPFC_SLI_MBOX_ACTIVE; + if (pmb->mbox_cmpl) + pmb->mbox_cmpl(phba, pmb); + } else { + /* Queue to worker thread to process */ + lpfc_mbox_cmpl_put(phba, pmb); + } } } else spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -12599,8 +13499,9 @@ send_current_mbox: MBX_NOWAIT); } while (rc == MBX_NOT_FINISHED); if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0349 rc should be " + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "0349 rc should be " "MBX_SUCCESS\n"); } @@ -12834,23 +13735,30 @@ lpfc_sli_intr_handler(int irq, void *dev_id) void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the els xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the els xri abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) { /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); /* Notify aborted XRI for ELS work queue */ lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri); + /* Free the event processed back to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); } /** @@ -12994,11 +13902,13 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; + spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); if (unlikely(!cmdiocbq)) { + spin_unlock_irqrestore(&pring->ring_lock, iflags); lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0386 ELS complete with no corresponding " "cmdiocb: 0x%x 0x%x 0x%x 0x%x\n", @@ -13008,7 +13918,6 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; } - spin_lock_irqsave(&pring->ring_lock, iflags); /* Put the iocb back on the txcmplq */ lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq); spin_unlock_irqrestore(&pring->ring_lock, iflags); @@ -13027,7 +13936,7 @@ lpfc_cq_event_setup(struct lpfc_hba *phba, void *entry, int size) /* Allocate a new internal CQ_EVENT entry */ cq_event = lpfc_sli4_cq_event_alloc(phba); if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0602 Failed to alloc CQ_EVENT entry\n"); return NULL; } @@ -13061,9 +13970,13 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe)); if (!cq_event) return false; - spin_lock_irqsave(&phba->hbalock, iflags); + + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); + /* Set the async event flag */ + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= ASYNC_EVENT; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -13102,7 +14015,7 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) spin_lock_irqsave(&phba->hbalock, iflags); pmb = phba->sli.mbox_active; if (unlikely(!pmb)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1832 No pending MBOX command to handle\n"); spin_unlock_irqrestore(&phba->hbalock, iflags); goto out_no_mqe_complete; @@ -13151,8 +14064,9 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc != MBX_BUSY) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0385 rc should " + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "0385 rc should " "have been MBX_BUSY\n"); if (rc != MBX_NOT_FINISHED) goto send_current_mbox; @@ -13162,7 +14076,26 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) phba->pport->work_port_events &= ~WORKER_MBOX_TMO; spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); - /* There is mailbox completion work to do */ + /* Do NOT queue MBX_HEARTBEAT to the worker thread for processing. */ + if (pmbox->mbxCommand == MBX_HEARTBEAT) { + spin_lock_irqsave(&phba->hbalock, iflags); + /* Release the mailbox command posting token */ + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + if (bf_get(lpfc_trailer_consumed, mcqe)) + lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + /* Post the next mbox command, if there is one */ + lpfc_sli4_post_async_mbox(phba); + + /* Process cmpl now */ + if (pmb->mbox_cmpl) + pmb->mbox_cmpl(phba, pmb); + return false; + } + + /* There is mailbox completion work to queue to the worker thread */ spin_lock_irqsave(&phba->hbalock, iflags); __lpfc_mbox_cmpl_put(phba, pmb); phba->work_ha |= HA_MBATT; @@ -13240,7 +14173,6 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_sli_ring *pring = cq->pring; int txq_cnt = 0; int txcmplq_cnt = 0; - int fcp_txcmplq_cnt = 0; /* Check for response status */ if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { @@ -13260,11 +14192,10 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, txq_cnt++; if (!list_empty(&pring->txcmplq)) txcmplq_cnt++; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " - "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n", + "els_txcmplq_cnt=%d\n", txq_cnt, phba->iocb_cnt, - fcp_txcmplq_cnt, txcmplq_cnt); return false; } @@ -13338,21 +14269,24 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, break; case LPFC_NVME_LS: /* NVME LS uses ELS resources */ case LPFC_ELS: - cq_event = lpfc_cq_event_setup( - phba, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); - if (!cq_event) - return false; + cq_event = lpfc_cq_event_setup(phba, wcqe, sizeof(*wcqe)); + if (!cq_event) { + workposted = false; + break; + } cq_event->hdwq = cq->hdwq; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Set the els xri abort event flag */ phba->hba_flag |= ELS_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); workposted = true; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0603 Invalid CQ subtype %d: " "%08x %08x %08x %08x\n", cq->subtype, wcqe->word0, wcqe->parameter, @@ -13363,7 +14297,7 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, return workposted; } -#define FC_RCTL_MDS_DIAGS 0xF4 +#define FC_RCTL_MDS_DIAGS 0xF4 /** * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry @@ -13381,7 +14315,9 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) struct fc_frame_header *fc_hdr; struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq; struct lpfc_queue *drq = phba->sli4_hba.dat_rq; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_nvmet_tgtport *tgtp; +#endif struct hbq_dmabuf *dma_buf; uint32_t status, rq_id; unsigned long iflags; @@ -13400,7 +14336,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) status = bf_get(lpfc_rcqe_status, rcqe); switch (status) { case FC_STATUS_RQ_BUF_LEN_EXCEEDED: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2537 Receive Frame Truncated!!\n"); /* fall through */ case FC_STATUS_RQ_SUCCESS: @@ -13416,13 +14352,18 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) hrq->RQ_buf_posted--; memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); + /* If a NVME LS event (type 0x28), treat it as Fast path */ fc_hdr = (struct fc_frame_header *)dma_buf->hbuf.virt; if (fc_hdr->fh_r_ctl == FC_RCTL_MDS_DIAGS || fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { spin_unlock_irqrestore(&phba->hbalock, iflags); /* Handle MDS Loopback frames */ - lpfc_sli4_handle_mds_loopback(phba->pport, dma_buf); + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_sli4_handle_mds_loopback(phba->pport, + dma_buf); + else + lpfc_in_buf_free(phba, &dma_buf->dbuf); break; } @@ -13434,10 +14375,11 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) spin_unlock_irqrestore(&phba->hbalock, iflags); workposted = true; break; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) case FC_STATUS_INSUFF_BUF_FRM_DISC: if (phba->nvmet_support) { tgtp = phba->targetport->private; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6402 RQE Error x%x, posted %d err_cnt " "%d: %x %x %x\n", status, hrq->RQ_buf_posted, @@ -13446,8 +14388,8 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) atomic_read(&tgtp->rcv_fcp_cmd_out), atomic_read(&tgtp->xmt_fcp_release)); } - /* fallthrough */ - +#endif + /* fall through */ case FC_STATUS_INSUFF_BUF_NEED_BUF: hrq->RQ_no_posted_buf++; /* Post more buffers if possible */ @@ -13509,7 +14451,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, (struct lpfc_rcqe *)&cqevt); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0388 Not a valid WCQE code: x%x\n", bf_get(lpfc_cqe_code, &cqevt)); break; @@ -13536,6 +14478,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, { struct lpfc_queue *cq = NULL, *childq; uint16_t cqid; + int ret = 0; /* Get the reference to the corresponding CQ */ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); @@ -13548,7 +14491,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, } if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0365 Slow-path CQ identifier " "(%d) does not exist\n", cqid); return; @@ -13557,9 +14500,14 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, /* Save EQ associated with this CQ */ cq->assoc_qp = speq; - if (!queue_work_on(cq->chann, phba->wq, &cq->spwork)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0390 Cannot schedule soft IRQ " + if (is_kdump_kernel()) + ret = queue_work(phba->wq, &cq->spwork); + else + ret = queue_work_on(cq->chann, phba->wq, &cq->spwork); + + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0390 Cannot schedule queue work " "for CQ eqcqid=%d, cqid=%d on CPU %d\n", cqid, cq->queue_id, raw_smp_processor_id()); } @@ -13570,6 +14518,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, * @cq: Pointer to CQ to be processed * @handler: Routine to process each cqe * @delay: Pointer to usdelay to set in case of rescheduling of the handler + * @poll_mode: Polling mode we were called from * * This routine processes completion queue entries in a CQ. While a valid * queue element is found, the handler is called. During processing checks @@ -13587,7 +14536,8 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, static bool __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, bool (*handler)(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_cqe *), unsigned long *delay) + struct lpfc_cqe *), unsigned long *delay, + enum lpfc_poll_mode poll_mode) { struct lpfc_cqe *cqe; bool workposted = false; @@ -13615,6 +14565,7 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed, LPFC_QUEUE_NOARM); consumed = 0; + cq->assoc_qp->q_flag |= HBA_EQ_DELAY_CHK; } if (count == LPFC_NVMET_CQ_NOTIFY) @@ -13627,6 +14578,10 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, arm = false; } + /* Note: complete the irq_poll softirq before rearming CQ */ + if (poll_mode == LPFC_IRQ_POLL) + irq_poll_complete(&cq->iop); + /* Track the max number of CQEs processed in 1 EQ */ if (count > cq->CQ_max_cqe) cq->CQ_max_cqe = count; @@ -13639,7 +14594,7 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, "0369 No entry from completion queue " "qid=%d\n", cq->queue_id); - cq->queue_claimed = 0; + xchg(&cq->queue_claimed, 0); rearm_and_exit: phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed, @@ -13675,20 +14630,20 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq) case LPFC_MCQ: workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_sp_handle_mcqe, - &delay); + &delay, LPFC_QUEUE_WORK); break; case LPFC_WCQ: if (cq->subtype == LPFC_IO) workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe, - &delay); + &delay, LPFC_QUEUE_WORK); else workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_sp_handle_cqe, - &delay); + &delay, LPFC_QUEUE_WORK); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0370 Invalid completion queue type (%d)\n", cq->type); return; @@ -13697,8 +14652,8 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq) if (delay) { if (!queue_delayed_work_on(cq->chann, phba->wq, &cq->sched_spwork, delay)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0394 Cannot schedule soft IRQ " + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0394 Cannot schedule queue work " "for cqid=%d on CPU %d\n", cq->queue_id, cq->chann); } @@ -13767,9 +14722,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, IOERR_NO_RESOURCES)) phba->lpfc_rampdown_queue_depth(phba); - /* Log the error status */ + /* Log the cmpl status */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0373 FCP CQE error: status=x%x: " + "0373 FCP CQE cmpl: status=x%x: " "CQE: %08x %08x %08x %08x\n", bf_get(lpfc_wcqe_c_status, wcqe), wcqe->word0, wcqe->total_data_placed, @@ -13779,9 +14734,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Look up the FCP command IOCB and create pseudo response IOCB */ spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; - spin_unlock_irqrestore(&pring->ring_lock, iflags); cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0374 FCP complete with no corresponding " @@ -13789,7 +14744,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, bf_get(lpfc_wcqe_c_request_tag, wcqe)); return; } -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) cmdiocbq->isr_timestamp = cq->isr_timestamp; #endif if (cmdiocbq->iocb_cmpl == NULL) { @@ -13814,12 +14769,6 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Fake the irspiocb and copy necessary response information */ lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - /* Pass the cmd_iocb and the rsp state to the upper layer */ (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); } @@ -13878,7 +14827,9 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_queue *drq; struct rqb_dmabuf *dma_buf; struct fc_frame_header *fc_hdr; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_nvmet_tgtport *tgtp; +#endif uint32_t status, rq_id; unsigned long iflags; uint32_t fctl, idx; @@ -13907,7 +14858,7 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, status = bf_get(lpfc_rcqe_status, rcqe); switch (status) { case FC_STATUS_RQ_BUF_LEN_EXCEEDED: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6126 Receive Frame Truncated!!\n"); /* fall through */ case FC_STATUS_RQ_SUCCESS: @@ -13944,10 +14895,11 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, drop: lpfc_rq_buf_free(phba, &dma_buf->hbuf); break; +#if defined(BUILD_NVME) && (IS_ENABLED(CONFIG_NVME_TARGET_FC)) case FC_STATUS_INSUFF_BUF_FRM_DISC: if (phba->nvmet_support) { tgtp = phba->targetport->private; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6401 RQE Error x%x, posted %d err_cnt " "%d: %x %x %x\n", status, hrq->RQ_buf_posted, @@ -13956,8 +14908,8 @@ drop: atomic_read(&tgtp->rcv_fcp_cmd_out), atomic_read(&tgtp->xmt_fcp_release)); } - /* fallthrough */ - +#endif + /* fall through */ case FC_STATUS_INSUFF_BUF_NEED_BUF: hrq->RQ_no_posted_buf++; /* Post more buffers if possible */ @@ -14021,7 +14973,7 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, } break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0144 Not a valid CQE code: x%x\n", bf_get(lpfc_wcqe_c_code, &wcqe)); break; @@ -14029,6 +14981,47 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, return workposted; } +/** + * lpfc_sli4_sched_cq_work - Schedules cq work + * @phba: Pointer to HBA context object. + * @cq: Pointer to CQ + * @cqid: CQ ID + * + * This routine checks the poll mode of the CQ corresponding to + * cq->chann, then either schedules a softirq or queue_work to complete + * cq work. + * + * queue_work path is taken if in NVMET mode, or if poll_mode is in + * LPFC_QUEUE_WORK mode. Otherwise, softirq path is taken. + * + **/ +static void lpfc_sli4_sched_cq_work(struct lpfc_hba *phba, + struct lpfc_queue *cq, uint16_t cqid) +{ + int ret = 0; + switch (cq->poll_mode) { + case LPFC_IRQ_POLL: + /* CGN mgmt is mutually exclusive from softirq processing */ + if (phba->cmf_active_mode == LPFC_CFG_OFF) { + irq_poll_sched(&cq->iop); + break; + } + /* fallthrough */ + case LPFC_QUEUE_WORK: + default: + if (is_kdump_kernel()) + ret = queue_work(phba->wq, &cq->irqwork); + else + ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork); + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0383 Cannot schedule queue work " + "for CQ eqcqid=%d, cqid=%d on CPU %d\n", + cqid, cq->queue_id, + raw_smp_processor_id()); + } +} + /** * lpfc_sli4_hba_handle_eqe - Process a fast-path event queue entry * @phba: Pointer to HBA context object. @@ -14050,7 +15043,7 @@ lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t cqid, id; if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0366 Not a valid completion " "event: majorcode=x%x, minorcode=x%x\n", bf_get_le32(lpfc_eqe_major_code, eqe), @@ -14093,7 +15086,7 @@ lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, process_cq: if (unlikely(cqid != cq->queue_id)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0368 Miss-matched fast-path completion " "queue identifier: eqcqid=%d, fcpcqid=%d\n", cqid, cq->queue_id); @@ -14107,16 +15100,13 @@ work_cq: else cq->isr_timestamp = 0; #endif - if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0363 Cannot schedule soft IRQ " - "for CQ eqcqid=%d, cqid=%d on CPU %d\n", - cqid, cq->queue_id, raw_smp_processor_id()); + lpfc_sli4_sched_cq_work(phba, cq, cqid); } /** * __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry * @cq: Pointer to CQ to be processed + * @poll_mode: Enum lpfc_poll_state to determine poll mode * * This routine calls the cq processing routine with the handler for * fast path CQEs. @@ -14130,7 +15120,8 @@ work_cq: * the delay indicates when to reschedule it. **/ static void -__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq) +__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq, + enum lpfc_poll_mode poll_mode) { struct lpfc_hba *phba = cq->phba; unsigned long delay; @@ -14138,15 +15129,15 @@ __lpfc_sli4_hba_process_cq(struct lpfc_queue *cq) /* process and rearm the CQ */ workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe, - &delay); + &delay, poll_mode); if (delay) { if (!queue_delayed_work_on(cq->chann, phba->wq, &cq->sched_irqwork, delay)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0367 Cannot schedule soft IRQ " - "for cqid=%d on CPU %d\n", - cq->queue_id, cq->chann); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0367 Cannot schedule queue work " + "for cqid=%d on CPU %d\n", + cq->queue_id, cq->chann); } /* wake up worker thread if there are works to be done */ @@ -14166,7 +15157,7 @@ lpfc_sli4_hba_process_cq(struct work_struct *work) { struct lpfc_queue *cq = container_of(work, struct lpfc_queue, irqwork); - __lpfc_sli4_hba_process_cq(cq); + __lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK); } /** @@ -14181,7 +15172,7 @@ lpfc_sli4_dly_hba_process_cq(struct work_struct *work) struct lpfc_queue *cq = container_of(to_delayed_work(work), struct lpfc_queue, sched_irqwork); - __lpfc_sli4_hba_process_cq(cq); + __lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK); } /** @@ -14220,7 +15211,6 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) int ecount = 0; int hba_eqidx; struct lpfc_eq_intr_info *eqi; - uint32_t icnt; /* Get the driver's phba structure from the dev_id */ hba_eq_hdl = (struct lpfc_hba_eq_hdl *)dev_id; @@ -14243,17 +15233,18 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) spin_lock_irqsave(&phba->hbalock, iflag); if (phba->link_state < LPFC_LINK_DOWN) /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, fpeq); + lpfc_sli4_eqcq_flush(phba, fpeq); spin_unlock_irqrestore(&phba->hbalock, iflag); return IRQ_NONE; } - eqi = phba->sli4_hba.eq_info; - icnt = this_cpu_inc_return(eqi->icnt); + eqi = this_cpu_ptr(phba->sli4_hba.eq_info); + eqi->icnt++; + fpeq->last_cpu = raw_smp_processor_id(); - if (icnt > LPFC_EQD_ISR_TRIGGER && - phba->cfg_irq_chann == 1 && + if (eqi->icnt > LPFC_EQD_ISR_TRIGGER && + fpeq->q_flag & HBA_EQ_DELAY_CHK && phba->cfg_auto_imax && fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY && phba->sli.sli_flag & LPFC_SLI_USE_EQDR) @@ -14320,9 +15311,17 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE; } /* lpfc_sli4_intr_handler */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void lpfc_sli4_poll_hbtimer(unsigned long ptr) +#else void lpfc_sli4_poll_hbtimer(struct timer_list *t) +#endif { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + struct lpfc_hba *phba = (struct lpfc_hba *)ptr; +#else struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer); +#endif struct lpfc_queue *eq; int i = 0; @@ -14368,12 +15367,10 @@ static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq) { struct lpfc_hba *phba = eq->phba; - if (list_empty(&phba->poll_list)) { - timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); - /* kickstart slowpath processing for this eq */ + /* kickstart slowpath processing if needed */ + if (list_empty(&phba->poll_list)) mod_timer(&phba->cpuhp_poll_timer, jiffies + msecs_to_jiffies(LPFC_POLL_HB)); - } list_add_rcu(&eq->_poll_list, &phba->poll_list); synchronize_rcu(); @@ -14431,7 +15428,7 @@ __lpfc_sli4_switch_eqmode(struct lpfc_queue *eq, uint8_t mode) * synchronization mechanism in place (queue_claimed) to * deal with it. This is just a draining phase for int- * errupt handler (not eq's) as we have guranteed through - * barrier that all the CPUs have seen the new CQ_POLLED + * barrier that all the cpu's have seen the new CQ_POLLED * state. which will effectively disable the REARMING of * the EQ. The whole idea is eq's die off eventually as * we are not rearming EQ's anymore. @@ -14676,7 +15673,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_FCP | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6428 Failed allocating mailbox cmd buffer." " EQ delay was not set.\n"); return; @@ -14718,7 +15715,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2512 MODIFY_EQ_DELAY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -14795,14 +15792,15 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) dmult); switch (eq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0360 Unsupported EQ count. (%d)\n", eq->entry_count); if (eq->entry_count < 256) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + /* otherwise default to smallest count */ + /* fall through */ case 256: bf_set(lpfc_eq_context_count, &eq_create->u.request.context, LPFC_EQ_CNT_256); @@ -14839,7 +15837,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2500 EQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -14858,6 +15856,15 @@ out: return status; } +static int lpfc_cq_poll_hdler(struct irq_poll *iop, int budget) +{ + struct lpfc_queue *cq = container_of(iop, struct lpfc_queue, iop); + + __lpfc_sli4_hba_process_cq(cq, LPFC_IRQ_POLL); + + return 1; +} + /** * lpfc_cq_create - Create a Completion Queue on the HBA * @phba: HBA structure that indicates port to create a queue on. @@ -14933,9 +15940,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, LPFC_CQ_CNT_WORD7); break; } - /* fall through */ + /* Fall Thru */ default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0361 Unsupported CQ count: " "entry cnt %d sz %d pg cnt %d\n", cq->entry_count, cq->entry_size, @@ -14944,7 +15951,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + /* otherwise default to smallest count */ + /* fall through */ case 256: bf_set(lpfc_cq_context_count, &cq_create->u.request.context, LPFC_CQ_CNT_256); @@ -14971,7 +15979,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2501 CQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -14997,6 +16005,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, if (cq->queue_id > phba->sli4_hba.cq_max) phba->sli4_hba.cq_max = cq->queue_id; + + irq_poll_init(&cq->iop, LPFC_IRQ_POLL_WEIGHT, lpfc_cq_poll_hdler); out: mempool_free(mbox, phba->mbox_mem_pool); return status; @@ -15056,7 +16066,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, LPFC_MBOX_OPCODE_FCOE_CQ_CREATE_SET, length, LPFC_SLI4_MBX_NEMBED); if (alloclen < length) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3098 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, length); @@ -15110,14 +16120,15 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, } /* fall through */ default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3118 Bad CQ count. (%d)\n", cq->entry_count); if (cq->entry_count < 256) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest */ + /* otherwise default to smallest (drop thru) */ + /* fall through */ case 256: bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_256); @@ -15228,7 +16239,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3119 CQ_CREATE_SET mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15386,14 +16397,15 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, cq->queue_id); switch (mq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0362 Unsupported MQ count. (%d)\n", mq->entry_count); if (mq->entry_count < 16) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + /* otherwise default to smallest count */ + /* fall through */ case 16: bf_set(lpfc_mq_context_ring_size, &mq_create_ext->u.request.context, @@ -15442,7 +16454,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2502 MQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15503,9 +16515,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, void __iomem *bar_memmap_p; uint32_t db_offset; uint16_t pci_barset; +#ifndef BUILD_BRCMFCOE uint8_t dpp_barset; uint32_t dpp_offset; - unsigned long pg_addr; +#endif uint8_t wq_create_version; /* sanity check on queue memory */ @@ -15539,12 +16552,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, else wq_create_version = LPFC_Q_CREATE_VERSION_0; - - if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) - wq_create_version = LPFC_Q_CREATE_VERSION_1; - else - wq_create_version = LPFC_Q_CREATE_VERSION_0; - switch (wq_create_version) { case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, @@ -15565,8 +16572,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_WQ_WQE_SIZE_128); break; } +#ifndef BUILD_BRCMFCOE /* Request DPP by default */ bf_set(lpfc_mbx_wq_create_dpp_req, &wq_create->u.request_1, 1); +#endif bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, (wq->page_size / SLI4_PAGE_SIZE)); @@ -15591,7 +16600,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2503 WQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15618,7 +16627,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, &wq_create->u.response); if ((wq->db_format != LPFC_DB_LIST_FORMAT) && (wq->db_format != LPFC_DB_RING_FORMAT)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3265 WQ[%d] doorbell format " "not supported: x%x\n", wq->queue_id, wq->db_format); @@ -15630,7 +16639,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3263 WQ[%d] failed to memmap " "pci barset:x%x\n", wq->queue_id, pci_barset); @@ -15640,7 +16649,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, db_offset = wq_create->u.response.doorbell_offset; if ((db_offset != LPFC_ULP0_WQ_DOORBELL) && (db_offset != LPFC_ULP1_WQ_DOORBELL)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3252 WQ[%d] doorbell offset " "not supported: x%x\n", wq->queue_id, db_offset); @@ -15654,6 +16663,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, pci_barset, db_offset, wq->db_format); } else wq->db_regaddr = phba->sli4_hba.WQDBregaddr; +#ifndef BUILD_BRCMFCOE } else { /* Check if DPP was honored by the firmware */ wq->dpp_enable = bf_get(lpfc_mbx_wq_create_dpp_rsp, @@ -15664,7 +16674,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3267 WQ[%d] failed to memmap " "pci barset:x%x\n", wq->queue_id, pci_barset); @@ -15679,40 +16689,30 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, &wq_create->u.response_1); bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, dpp_barset); - if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3268 WQ[%d] failed to memmap " - "pci barset:x%x\n", - wq->queue_id, dpp_barset); - status = -ENOMEM; - goto out; - } - dpp_offset = wq_create->u.response_1.dpp_offset; - wq->dpp_regaddr = bar_memmap_p + dpp_offset; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + if (bar_memmap_p) { + dpp_offset = wq_create->u.response_1.dpp_offset; + wq->dpp_regaddr = bar_memmap_p + dpp_offset; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3271 WQ[%d]: barset:x%x, offset:x%x, " "dpp_id:x%x dpp_barset:x%x " "dpp_offset:x%x\n", wq->queue_id, pci_barset, db_offset, wq->dpp_id, dpp_barset, dpp_offset); - - /* Enable combined writes for DPP aperture */ - pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK; -#ifdef CONFIG_X86 - rc = set_memory_wc(pg_addr, 1); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3272 Cannot setup Combined " - "Write on WQ[%d] - disable DPP\n", - wq->queue_id); + } else { phba->cfg_enable_dpp = 0; + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3268 WQ[%d] dpp memmap " + "unavailable pci barset:x%x\n", + wq->queue_id, dpp_barset); } -#else - phba->cfg_enable_dpp = 0; -#endif } else wq->db_regaddr = phba->sli4_hba.WQDBregaddr; + } +#else + } else { + wq->db_regaddr = phba->sli4_hba.WQDBregaddr; } +#endif wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (wq->pring == NULL) { status = -ENOMEM; @@ -15804,14 +16804,15 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, } else { switch (hrq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2535 Unsupported RQ count. (%d)\n", hrq->entry_count); if (hrq->entry_count < 512) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + /* otherwise default to smallest count */ + /* fall through */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, @@ -15855,7 +16856,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2504 RQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15873,7 +16874,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.response); if ((hrq->db_format != LPFC_DB_LIST_FORMAT) && (hrq->db_format != LPFC_DB_RING_FORMAT)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3262 RQ [%d] doorbell format not " "supported: x%x\n", hrq->queue_id, hrq->db_format); @@ -15885,7 +16886,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.response); bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3269 RQ[%d] failed to memmap pci " "barset:x%x\n", hrq->queue_id, pci_barset); @@ -15896,7 +16897,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, db_offset = rq_create->u.response.doorbell_offset; if ((db_offset != LPFC_ULP0_RQ_DOORBELL) && (db_offset != LPFC_ULP1_RQ_DOORBELL)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3270 RQ[%d] doorbell offset not " "supported: x%x\n", hrq->queue_id, db_offset); @@ -15941,14 +16942,15 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, } else { switch (drq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2536 Unsupported RQ count. (%d)\n", drq->entry_count); if (drq->entry_count < 512) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + /* otherwise default to smallest count */ + /* fall through */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, @@ -16078,7 +17080,7 @@ lpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp, LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, length, LPFC_SLI4_MBX_NEMBED); if (alloclen < length) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3099 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, length); @@ -16188,7 +17190,7 @@ lpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3120 RQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16258,7 +17260,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2505 EQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16313,7 +17315,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2506 CQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16367,7 +17369,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2507 MQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16420,7 +17422,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2508 WQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16477,11 +17479,12 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2509 RQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); - mempool_free(mbox, hrq->phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, hrq->phba->mbox_mem_pool); return -ENXIO; } bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, @@ -16492,7 +17495,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2510 RQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16540,7 +17543,7 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, union lpfc_sli4_cfg_shdr *shdr; if (xritag == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0364 Invalid param:\n"); return -EINVAL; } @@ -16578,12 +17581,10 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (!phba->sli4_hba.intr_enable) - mempool_free(mbox, phba->mbox_mem_pool); - else if (rc != MBX_TIMEOUT) + if (rc != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2511 POST_SGL mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16714,7 +17715,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, reqlen = post_cnt * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2559 Block sgl registration required DMA " "size (%d) great than a page\n", reqlen); return -ENOMEM; @@ -16730,7 +17731,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0285 Allocated DMA memory size (%d) is " "less than the requested DMA memory " "size (%d)\n", alloclen, reqlen); @@ -16775,12 +17776,10 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (!phba->sli4_hba.intr_enable) - lpfc_sli4_mbox_cmd_free(phba, mbox); - else if (rc != MBX_TIMEOUT) + if (rc != MBX_TIMEOUT) lpfc_sli4_mbox_cmd_free(phba, mbox); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2513 POST_SGL_BLOCK mailbox command failed " "status x%x add_status x%x mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16828,7 +17827,7 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6119 Failed to allocate mbox cmd memory\n"); return -ENOMEM; } @@ -16839,7 +17838,7 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, reqlen, LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6120 Allocated DMA memory size (%d) is " "less than the requested DMA memory " "size (%d)\n", alloclen, reqlen); @@ -16890,12 +17889,10 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, shdr = (union lpfc_sli4_cfg_shdr *)&sgl->cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (!phba->sli4_hba.intr_enable) - lpfc_sli4_mbox_cmd_free(phba, mbox); - else if (rc != MBX_TIMEOUT) + if (rc != MBX_TIMEOUT) lpfc_sli4_mbox_cmd_free(phba, mbox); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6125 POST_SGL_BLOCK mailbox command failed " "status x%x add_status x%x mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -17049,8 +18046,6 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) struct fc_vft_header *fc_vft_hdr; uint32_t *header = (uint32_t *) fc_hdr; -#define FC_RCTL_MDS_DIAGS 0xF4 - switch (fc_hdr->fh_r_ctl) { case FC_RCTL_DD_UNCAT: /* uncategorized information */ case FC_RCTL_DD_SOL_DATA: /* solicited data */ @@ -17078,7 +18073,6 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) case FC_RCTL_F_BSY: /* fabric busy to data frame */ case FC_RCTL_F_BSYL: /* fabric busy to link control frame */ case FC_RCTL_LCR: /* link credit reset */ - case FC_RCTL_MDS_DIAGS: /* MDS Diagnostics */ case FC_RCTL_END: /* end */ break; case FC_RCTL_VFTH: /* Virtual Fabric tagging Header */ @@ -17473,12 +18467,13 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, if (cmd_iocbq) { ndlp = (struct lpfc_nodelist *)cmd_iocbq->context1; lpfc_nlp_put(ndlp); + lpfc_nlp_not_used(ndlp); lpfc_sli_release_iocbq(phba, cmd_iocbq); } /* Failure means BLS ABORT RSP did not get delivered to remote node*/ if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3154 BLS ABORT RSP failed, data: x%x/x%x\n", rsp_iocbq->iocb.ulpStatus, rsp_iocbq->iocb.un.ulpWord[4]); @@ -17640,7 +18635,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); if (rc == IOCB_ERROR) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2925 Failed to issue CT ABTS RSP x%x on " "xri x%x, Data x%x\n", icmd->un.xseq64.w5.hcsw.Rctl, oxid, @@ -17890,7 +18885,7 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; iocbq = lpfc_prep_seq(vport, seq_dmabuf); if (!iocbq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2707 Ring %d handler: Failed to allocate " "iocb Rctl x%x Type x%x received\n", LPFC_ELS_RING, @@ -17901,7 +18896,7 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, phba->sli4_hba.els_wq->pring, iocbq, fc_hdr->fh_r_ctl, fc_hdr->fh_type)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2540 Ring %d handler: unexpected Rctl " "x%x Type x%x received\n", LPFC_ELS_RING, @@ -18045,7 +19040,10 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { vport = phba->pport; /* Handle MDS Loopback frames */ - lpfc_sli4_handle_mds_loopback(vport, dmabuf); + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_sli4_handle_mds_loopback(vport, dmabuf); + else + lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } @@ -18063,17 +19061,6 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); - if (fc_hdr->fh_r_ctl == 0xF4 && fc_hdr->fh_type == 0xFF) { - vport = phba->pport; - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2023 MDS Loopback %d bytes\n", - bf_get(lpfc_rcqe_length, - &dmabuf->cq_event.cqe.rcqe_cmpl)); - /* Handle MDS Loopback frames */ - lpfc_sli4_handle_mds_loopback(vport, dmabuf); - return; - } - /* d_id this frame is directed to */ did = sli4_did_from_fc_hdr(fc_hdr); @@ -18166,7 +19153,7 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2008 Error %d posting all rpi " "headers\n", rc); rc = -EIO; @@ -18212,7 +19199,7 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) /* The port is notified of the header region via a mailbox command. */ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2001 Unable to allocate memory for issuing " "SLI_CONFIG_SPECIAL mailbox command\n"); return -ENOMEM; @@ -18239,9 +19226,10 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2514 POST_RPI_HDR mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -18296,8 +19284,9 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) phba->sli4_hba.max_cfg_param.rpi_used++; phba->sli4_hba.rpi_count++; } - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0001 rpi:%x max:%x lim:%x\n", + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0001 Allocated rpi:x%x max:x%x lim:x%x\n", (int) rpi, max_rpi, rpi_limit); /* @@ -18330,7 +19319,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2002 Error Could not grow rpi " "count\n"); } else { @@ -18364,7 +19353,8 @@ __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) phba->sli4_hba.rpi_count--; phba->sli4_hba.max_cfg_param.rpi_used--; } else { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "2016 rpi %x not inuse\n", rpi); } @@ -18431,7 +19421,7 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, mboxq->vport = ndlp->vport; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2010 Resume RPI Mailbox failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, &mboxq->u.mqe)); @@ -18466,7 +19456,7 @@ lpfc_sli4_init_vpi(struct lpfc_vport *vport) mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); if (rc != MBX_SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2022 INIT VPI Mailbox failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, &mboxq->u.mqe)); @@ -18502,7 +19492,7 @@ lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) if ((shdr_status || shdr_add_status) && (shdr_status != STATUS_FCF_IN_USE)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2558 ADD_FCF_RECORD mailbox failed with " "status x%x add_status x%x\n", shdr_status, shdr_add_status); @@ -18532,7 +19522,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2009 Failed to allocate mbox for ADD_FCF cmd\n"); return -ENOMEM; } @@ -18545,7 +19535,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) LPFC_MBOX_OPCODE_FCOE_ADD_FCF, req_len, LPFC_SLI4_MBX_NEMBED); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2523 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -18578,7 +19568,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2515 ADD_FCF_RECORD mailbox failed with " "status 0x%x\n", rc); lpfc_sli4_mbox_cmd_free(phba, mboxq); @@ -18651,7 +19641,7 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag; mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2000 Failed to allocate mbox for " "READ_FCF cmd\n"); error = -ENOMEM; @@ -19094,7 +20084,7 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2745 Failed to allocate mbox for " "requesting FCF rediscover.\n"); return -ENOMEM; @@ -19162,14 +20152,14 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; uint32_t offset = 0; - int rc; + int i, rc; if (!rgn23_data) return 0; pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2600 failed to allocate mailbox memory\n"); return 0; } @@ -19192,14 +20182,14 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) */ if (mb->un.varDmp.word_cnt == 0) break; - if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; + i = mb->un.varDmp.word_cnt * sizeof(uint32_t); + if (offset + i > DMP_RGN23_SIZE) + i = DMP_RGN23_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - rgn23_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); + rgn23_data + offset, i); + offset += i; + } while (offset < DMP_RGN23_SIZE); mempool_free(pmb, phba->mbox_mem_pool); return offset; @@ -19228,7 +20218,7 @@ lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3105 failed to allocate mailbox memory\n"); return 0; } @@ -19292,7 +20282,7 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) /* Check the region signature first */ if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2619 Config region 23 has bad signature\n"); goto out; } @@ -19300,7 +20290,7 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) /* Check the data structure version */ if (rgn23_data[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2620 Config region 23 has bad version\n"); goto out; } @@ -19355,6 +20345,465 @@ out: return; } +/** + * lpfc_log_fw_write_cmpl - logs firmware write completion status + * @phba: pointer to lpfc hba data structure + * @shdr_status: wr_object rsp's status field + * @shdr_add_status: wr_object rsp's add_status field + * @shdr_add_status_2: wr_object rsp's add_status_2 field + * @shdr_change_status: wr_object rsp's change_status field + * @shdr_csf: wr_object rsp's csf bit + * + * This routine is intended to be called after a firmware write completes. + * It will log next action items to be performed by the user to instantiate + * the newly downloaded firmware or reason for incompatibility. + **/ +static void +lpfc_log_fw_write_cmpl(struct lpfc_hba *phba, u32 shdr_status, + u32 shdr_add_status, u32 shdr_add_status_2, + u32 shdr_change_status, u32 shdr_csf) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "4198 %s: flash_id x%02x, asic_rev x%02x, " + "status x%02x, add_status x%02x, add_status_2 x%02x, " + "change_status x%02x, csf %01x\n", __func__, + phba->sli4_hba.flash_id, phba->sli4_hba.asic_rev, + shdr_status, shdr_add_status, shdr_add_status_2, + shdr_change_status, shdr_csf); + + if (shdr_add_status == LPFC_ADD_STATUS_INCOMPAT_OBJ) { + switch (shdr_add_status_2) { + case LPFC_ADD_STATUS_2_INCOMPAT_FLASH: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4199 Firmware write failed: " + "image incompatible with flash x%02x\n", + phba->sli4_hba.flash_id); + break; + case LPFC_ADD_STATUS_2_INCORRECT_ASIC: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4200 Firmware write failed: " + "image incompatible with ASIC " + "architecture x%02x\n", + phba->sli4_hba.asic_rev); + break; + default: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4210 Firmware write failed: " + "add_status_2 x%02x\n", + shdr_add_status_2); + break; + } + } else if (!shdr_status && !shdr_add_status) { + if (shdr_change_status == LPFC_CHANGE_STATUS_FW_RESET || + shdr_change_status == LPFC_CHANGE_STATUS_PORT_MIGRATION) { + if (shdr_csf) + shdr_change_status = + LPFC_CHANGE_STATUS_PCI_RESET; + } + + switch (shdr_change_status) { + case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3198 Firmware write complete: System " + "reboot required to instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_FW_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3199 Firmware write complete: Firmware" + " reset required to instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_PORT_MIGRATION): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3200 Firmware write complete: Port " + "Migration or PCI Reset required to " + "instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_PCI_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3201 Firmware write complete: PCI " + "Reset required to instantiate\n"); + break; + default: + break; + } + } +} + +#ifndef BUILD_BRCMFCOE +/** + * lpfc_del_object - delete an object maintained by the firmware + * @phba: HBA structure that indicates port to create a queue on. + * @obj_str: Object name. + * + * This routine will create a delete_object mailbox command to send to the port. + * + * Return 0 is successful. + * Return negative value for error cases. + **/ +int +lpfc_del_object(struct lpfc_hba *phba, char *obj_str) +{ + struct lpfc_mbx_del_object *del_object; + LPFC_MBOXQ_t *mbox; + int rc = 0, i = 0; + uint32_t shdr_status, shdr_add_status; + uint32_t mbox_tmo; + union lpfc_sli4_cfg_shdr *shdr; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox || !obj_str) + return -ENOMEM; + + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_DELETE_OBJECT, + sizeof(struct lpfc_mbx_del_object) - + sizeof(struct lpfc_sli4_cfg_mhdr), + LPFC_SLI4_MBX_EMBED); + + del_object = (struct lpfc_mbx_del_object *)&mbox->u.mqe.un.del_object; + sprintf((uint8_t *)del_object->request.object_name, obj_str); + for (i = 0; i < LPFC_MBX_OBJECT_NAME_LEN_DW; i++) + del_object->request.object_name[i] = + cpu_to_le32(del_object->request.object_name[i]); + + if (!phba->sli4_hba.intr_enable) { + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + } else { + mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *)&del_object->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_AUTH, + "3034 Delete Object mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_auth_issue_rd_object - read an object from the firmware + * @phba: HBA structure that indicates port to create a queue on. + * @dmabuf_list: list of dmabufs for object to be read from the port. + * @size: the total byte value of the object to be read. + * @offset: the current offset to be used to start the transfer. + * @obj_str: pointer to the object name. + * + * This routine will create a rd_object mailbox command to send to the port. + * the mailbox command will be constructed using the dma buffers described in + * @dmabuf_list to create a list of BDEs. This routine will fill in as many + * BDEs that the non-embedded mailbox can support. The @offset variable will be + * used to indicate the starting offset of the transfer and will also return + * the offset after the read object mailbox has completed. The size reported + * in the response and the eof bit can used to determine the end of the object. + * + * Return 0 is successful and offset will contain the the new offset to use + * for the next read. + * Return negative value for error cases. + **/ +int +lpfc_auth_issue_rd_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, + uint32_t size, uint32_t *offset, char *obj_str) +{ + struct lpfc_dmabuf *dmabuf; + struct lpfc_mbx_auth_rd_object *rd_object; + LPFC_MBOXQ_t *mbox; + uint32_t alloclen, reqlen; + uint32_t xfersize = 0; + int rc = 0, i = 0, j; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + reqlen = sizeof(struct lpfc_mbx_auth_rd_object); + alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_READ_OBJECT, reqlen, + LPFC_SLI4_MBX_NEMBED); + if (alloclen < reqlen) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_AUTH, + "3035 Allocated DMA memory size (%d) is " + "less than requested (%d)\n", + alloclen, reqlen); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + + rd_object = (struct lpfc_mbx_auth_rd_object *)mbox->sge_array->addr[0]; + rd_object->u.request.read_offset = *offset; + sprintf((uint8_t *)rd_object->u.request.object_name, obj_str); + for (j = 0; j < LPFC_MBX_OBJECT_NAME_LEN_DW; j++) + rd_object->u.request.object_name[j] = + cpu_to_le32(rd_object->u.request.object_name[j]); + + list_for_each_entry(dmabuf, dmabuf_list, list) { + if (i >= LPFC_MBX_AUTH_RD_CONFIG_MAX_BDE || xfersize >= size) + break; + rd_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys); + rd_object->u.request.bde[i].addrHigh = + putPaddrHigh(dmabuf->phys); + if (xfersize + SLI4_PAGE_SIZE >= size) { + rd_object->u.request.bde[i].tus.f.bdeSize = + (size - xfersize); + xfersize += (size - xfersize); + } else { + rd_object->u.request.bde[i].tus.f.bdeSize = + SLI4_PAGE_SIZE; + xfersize += SLI4_PAGE_SIZE; + } + i++; + } + rd_object->u.request.bde_count = i; + bf_set(lpfc_rd_object_read_length, &rd_object->u.request, size); + + mbox->mbox_cmpl = lpfc_auth_cmpl_rd_object; + mbox->vport = phba->pport; + mbox->ctx_buf = dmabuf_list; + mbox->ctx_ndlp = NULL; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + rc = -ENXIO; + goto fail; + } + return rc; + +fail: + if (mbox) + lpfc_sli4_mbox_cmd_free(phba, mbox); + return rc; +} + +/** + * lpfc_auth_rd_object - read an object from the firmware + * @phba: HBA structure that indicates port to create a queue on. + * @dmabuf_list: list of dmabufs to write to the port. + * @size: the total byte value of the objects to write to the port. + * @offset: the current offset to be used to start the transfer. + * @obj_str: Object name. + * + * This routine will create a rd_object mailbox command to send to the port. + * the mailbox command will be constructed using the dma buffers described in + * @dmabuf_list to create a list of BDEs. This routine will fill in as many + * BDEs that the embedded mailbox can support. The @offset variable will be + * used to indicate the starting offset of the transfer and will also return + * the offset after the read object mailbox has completed. + * + * Return 0 is successful and offset will contain the the new offset to use + * for the next read. + * Return negative value for error cases. + **/ +int +lpfc_auth_rd_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, + uint32_t size, uint32_t *offset, char *obj_str) +{ + struct lpfc_mbx_auth_rd_object *rd_object; + LPFC_MBOXQ_t *mbox; + uint32_t shdr_status, shdr_add_status; + uint32_t mbox_tmo; + union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_dmabuf *dmabuf; + uint32_t alloclen, reqlen; + uint32_t xfersize = 0; + int rc = 0, i = 0, j; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + reqlen = sizeof(struct lpfc_mbx_auth_rd_object); + alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_READ_OBJECT, reqlen, + LPFC_SLI4_MBX_NEMBED); + if (alloclen < reqlen) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_AUTH, + "3036 Allocated DMA memory size (%d) is " + "less than requested (%d)\n", + alloclen, reqlen); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + + rd_object = (struct lpfc_mbx_auth_rd_object *)mbox->sge_array->addr[0]; + rd_object->u.request.read_offset = *offset; + sprintf((uint8_t *)rd_object->u.request.object_name, obj_str); + for (j = 0; j < LPFC_MBX_OBJECT_NAME_LEN_DW; j++) + rd_object->u.request.object_name[j] = + cpu_to_le32(rd_object->u.request.object_name[j]); + + list_for_each_entry(dmabuf, dmabuf_list, list) { + if (i >= LPFC_MBX_AUTH_RD_CONFIG_MAX_BDE || xfersize >= size) + break; + rd_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys); + rd_object->u.request.bde[i].addrHigh = + putPaddrHigh(dmabuf->phys); + if (xfersize + SLI4_PAGE_SIZE >= size) { + rd_object->u.request.bde[i].tus.f.bdeSize = + (size - xfersize); + xfersize += (size - xfersize); + } else { + rd_object->u.request.bde[i].tus.f.bdeSize = + SLI4_PAGE_SIZE; + xfersize += SLI4_PAGE_SIZE; + } + i++; + } + rd_object->u.request.bde_count = i; + bf_set(lpfc_rd_object_read_length, &rd_object->u.request, xfersize); + if (!phba->sli4_hba.intr_enable) { + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + } else { + mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = &rd_object->cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + *offset += rd_object->u.response.actual_read_length; + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_AUTH, + "3037 Read Object mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + *offset = shdr_add_status; + } + return rc; +} + +/** + * lpfc_auth_wr_object - write an object to the firmware + * @phba: HBA structure that indicates port to create a queue on. + * @dmabuf_list: list of dmabufs to write to the port. + * @size: the total byte value of the objects to write to the port. + * @offset: the current offset to be used to start the transfer. + * @obj_str: Object group/name. + * + * This routine will create a wr_object mailbox command to send to the port. + * the mailbox command will be constructed using the dma buffers described in + * @dmabuf_list to create a list of BDEs. This routine will fill in as many + * BDEs that the non-embedded mailbox can support. The @offset variable will be + * used to indicate the starting offset of the transfer and will also return + * the offset after the write object mailbox has completed. @size is used to + * determine the end of the object and whether the eof bit should be set. + * + * Return 0 is successful and offset will contain the the new offset to use + * for the next write. + * Return negative value for error cases. + **/ +int +lpfc_auth_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, + uint32_t size, uint32_t *offset, char *obj_str) +{ + struct lpfc_mbx_auth_wr_object *wr_object; + LPFC_MBOXQ_t *mbox; + int rc = 0, i = 0, j; + uint32_t shdr_status, shdr_add_status, shdr_add_status_2; + uint32_t shdr_change_status = 0, shdr_csf = 0; + uint32_t mbox_tmo; + struct lpfc_dmabuf *dmabuf; + uint32_t written = 0; + uint32_t alloclen, reqlen; + bool check_change_status = false; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + reqlen = sizeof(struct lpfc_mbx_auth_wr_object); + alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_WRITE_OBJECT, reqlen, + LPFC_SLI4_MBX_NEMBED); + if (alloclen < reqlen) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI | LOG_AUTH, + "3038 Allocated DMA memory size (%d) is " + "less than the requested DMA memory size " + "(%d)\n", alloclen, reqlen); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + + wr_object = (struct lpfc_mbx_auth_wr_object *)mbox->sge_array->addr[0]; + wr_object->u.request.write_offset = *offset; + sprintf((uint8_t *)wr_object->u.request.object_name, obj_str); + for (j = 0; j < LPFC_MBX_OBJECT_NAME_LEN_DW; j++) + wr_object->u.request.object_name[j] = + cpu_to_le32(wr_object->u.request.object_name[j]); + bf_set(lpfc_wr_object_eof, &wr_object->u.request, 0); + list_for_each_entry(dmabuf, dmabuf_list, list) { + if (i >= LPFC_MBX_AUTH_WR_CONFIG_MAX_BDE || written >= size) + break; + wr_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys); + wr_object->u.request.bde[i].addrHigh = + putPaddrHigh(dmabuf->phys); + if (written + SLI4_PAGE_SIZE >= size) { + wr_object->u.request.bde[i].tus.f.bdeSize = + (size - written); + written += (size - written); + bf_set(lpfc_wr_object_eof, &wr_object->u.request, 1); + bf_set(lpfc_wr_object_eas, &wr_object->u.request, 1); + check_change_status = true; + } else { + wr_object->u.request.bde[i].tus.f.bdeSize = + SLI4_PAGE_SIZE; + written += SLI4_PAGE_SIZE; + } + i++; + } + wr_object->u.request.bde_count = i; + bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written); + + if (!phba->sli4_hba.intr_enable) { + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + } else { + mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr_status = bf_get(lpfc_mbox_hdr_status, + &wr_object->cfg_shdr.response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &wr_object->cfg_shdr.response); + shdr_add_status_2 = bf_get(lpfc_mbox_hdr_add_status_2, + &wr_object->cfg_shdr.response); + if (check_change_status) { + shdr_change_status = bf_get(lpfc_wr_object_change_status, + &wr_object->u.response); + shdr_csf = bf_get(lpfc_wr_object_csf, + &wr_object->u.response); + } + *offset += wr_object->u.response.actual_write_length; + if (rc != MBX_TIMEOUT) + lpfc_sli4_mbox_cmd_free(phba, mbox); + if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_AUTH, + "3039 Write Object mailbox failed with " + "status x%x add_status x%x, add_status_2 x%x, " + "mbx status x%x\n", + shdr_status, shdr_add_status, shdr_add_status_2, + rc); + rc = -ENXIO; + *offset = shdr_add_status; + } + + if (rc || check_change_status) + lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status, + shdr_add_status_2, shdr_change_status, + shdr_csf); + return rc; +} +#endif + /** * lpfc_wr_object - write an object to the firmware * @phba: HBA structure that indicates port to create a queue on. @@ -19381,7 +20830,8 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, struct lpfc_mbx_wr_object *wr_object; LPFC_MBOXQ_t *mbox; int rc = 0, i = 0; - uint32_t shdr_status, shdr_add_status, shdr_change_status; + uint32_t shdr_status, shdr_add_status, shdr_add_status_2; + uint32_t shdr_change_status = 0, shdr_csf = 0; uint32_t mbox_tmo; struct lpfc_dmabuf *dmabuf; uint32_t written = 0; @@ -19435,48 +20885,34 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, &wr_object->header.cfg_shdr.response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &wr_object->header.cfg_shdr.response); + shdr_add_status_2 = bf_get(lpfc_mbox_hdr_add_status_2, + &wr_object->header.cfg_shdr.response); if (check_change_status) { shdr_change_status = bf_get(lpfc_wr_object_change_status, &wr_object->u.response); - switch (shdr_change_status) { - case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3198 Firmware write complete: System " - "reboot required to instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_FW_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3199 Firmware write complete: Firmware" - " reset required to instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_PORT_MIGRATION): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3200 Firmware write complete: Port " - "Migration or PCI Reset required to " - "instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_PCI_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3201 Firmware write complete: PCI " - "Reset required to instantiate\n"); - break; - default: - break; - } + shdr_csf = bf_get(lpfc_wr_object_csf, + &wr_object->u.response); } - if (!phba->sli4_hba.intr_enable) + + if (rc != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); - else if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3025 Write Object mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); + "status x%x add_status x%x, add_status_2 x%x, " + "mbx status x%x\n", + shdr_status, shdr_add_status, shdr_add_status_2, + rc); rc = -ENXIO; *offset = shdr_add_status; - } else + } else { *offset += wr_object->u.response.actual_write_length; + } + + if (rc || check_change_status) + lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status, + shdr_add_status_2, shdr_change_status, + shdr_csf); return rc; } @@ -19649,7 +21085,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq = lpfc_sli_ringtx_get(phba, pring); if (!piocbq) { spin_unlock_irqrestore(&pring->ring_lock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2823 txq empty and txq_cnt is %d\n ", txq_cnt); break; @@ -19678,7 +21114,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) if (fail_msg) { /* Failed means we can't issue and need to cancel */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2822 IOCB failed %s iotag 0x%x " "xri 0x%x\n", fail_msg, @@ -19870,7 +21306,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } /* NVME_FCREQ and NVME_ABTS requests */ - if (pwqe->iocb_flag & LPFC_IO_NVME) { + if (pwqe->iocb_flag & LPFC_IO_NVME || + pwqe->iocb_flag & LPFC_IO_CMF) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ wq = qp->io_wq; pring = wq->pring; @@ -20280,6 +21717,10 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, lpfc_ncmd->cur_iocbq.wqe_cmpl = NULL; lpfc_ncmd->cur_iocbq.iocb_cmpl = NULL; + /* First Burst initial and total transfer length must be zeroed. */ + lpfc_ncmd->cur_iocbq.wqe.words[4] = 0; + lpfc_ncmd->cur_iocbq.wqe.words[5] = 0; + if (phba->cfg_xpsgl && !phba->nvmet_support && !list_empty(&lpfc_ncmd->dma_sgl_xtra_list)) lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); @@ -20348,8 +21789,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, list_add_tail(&lpfc_ncmd->list, &qp->lpfc_io_buf_list_put); qp->put_io_bufs++; - spin_unlock_irqrestore(&qp->io_buf_list_put_lock, - iflag); + spin_unlock_irqrestore(&qp->io_buf_list_put_lock, iflag); } } @@ -20566,6 +22006,227 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, return lpfc_cmd; } +/** + * lpfc_read_object - Retrieve object data from HBA + * @phba: The HBA for which this call is being executed. + * @rdobject: Pathname of object data we want to read. + * @datap: Pointer to where data will be copied to. + * @datasz: size of data area + * + * This routine is limited to object sizes of LPFC_BPL_SIZE (1024) or less. + * The data will be truncated if datasz is not large enough. + * Version 1 is not supported with Embedded mbox cmd, so we must use version 0. + * Returns the actual bytes read from the object. + */ +int +lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap, + uint32_t datasz) +{ + struct lpfc_mbx_read_object *read_object; + LPFC_MBOXQ_t *mbox; + int rc, length, eof, j, byte_cnt = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_dmabuf *pcmd; + + /* sanity check on queue memory */ + if (!datap) + return -ENODEV; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_read_object) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_READ_OBJECT, + length, LPFC_SLI4_MBX_EMBED); + read_object = &mbox->u.mqe.un.read_object; + shdr = (union lpfc_sli4_cfg_shdr *)&read_object->header.cfg_shdr; + + bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_Q_CREATE_VERSION_0); + bf_set(lpfc_mbx_rd_object_rlen, &read_object->u.request, datasz); + read_object->u.request.rd_object_offset = 0; + read_object->u.request.rd_object_cnt = 1; + + memset((void *)read_object->u.request.rd_object_name, 0, + LPFC_OBJ_NAME_SZ); + sprintf((uint8_t *)read_object->u.request.rd_object_name, rdobject); + for (j = 0; j < strlen(rdobject); j++) + read_object->u.request.rd_object_name[j] = + cpu_to_le32(read_object->u.request.rd_object_name[j]); + + pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) { + kfree(pcmd); + mempool_free(mbox, phba->mbox_mem_pool); + return -ENOMEM; + } + memset((void *)pcmd->virt, 0, LPFC_BPL_SIZE); + read_object->u.request.rd_object_hbuf[0].pa_lo = + putPaddrLow(pcmd->phys); + read_object->u.request.rd_object_hbuf[0].pa_hi = + putPaddrHigh(pcmd->phys); + read_object->u.request.rd_object_hbuf[0].length = LPFC_BPL_SIZE; + + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->ctx_buf = NULL; + mbox->ctx_ndlp = NULL; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + + if (shdr_status == STATUS_FAILED && + shdr_add_status == ADD_STATUS_INVALID_OBJECT_NAME) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "4674 No port cfg file in FW.\n"); + byte_cnt = -ENOENT; + } else if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "2625 READ_OBJECT mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + byte_cnt = -ENXIO; + } else { + /* Success */ + length = read_object->u.response.rd_object_actual_rlen; + eof = bf_get(lpfc_mbx_rd_object_eof, &read_object->u.response); + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_CGN_MGMT, + "2626 READ_OBJECT Success len %d:%d, EOF %d\n", + length, datasz, eof); + + /* Detect the port config file exists but is empty */ + if (!length && eof) { + byte_cnt = 0; + goto exit; + } + + byte_cnt = length; + lpfc_sli_pcimem_bcopy(pcmd->virt, datap, byte_cnt); + } + + exit: + lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); + kfree(pcmd); + mempool_free(mbox, phba->mbox_mem_pool); + return byte_cnt; +} + +/** + * lpfc_write_object - Retrieve object data from HBA + * @phba: The HBA for which this call is being executed. + * @rdobject: Pathname of object data we want to write. + * @datap: Pointer to where data will be copied from. + * @datasz: size of data area + * + * This routine is limited to object sizes of LPFC_BPL_SIZE (1024) or less. + * Version 1 is not supported with Embedded mbox cmd, so we must use version 0. + * Returns the actual bytes written to the object. + */ +int +lpfc_write_object(struct lpfc_hba *phba, char *wrobject, uint32_t *datap, + uint32_t datasz) +{ + struct lpfc_mbx_write_object *write_object; + LPFC_MBOXQ_t *mbox; + int rc, length, j, byte_cnt = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_dmabuf *pcmd; + + /* sanity check on queue memory */ + if (!datap) + return -ENODEV; + + if (datasz > LPFC_BPL_SIZE) + return -ENOSPC; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_write_object) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_WRITE_OBJECT, + length, LPFC_SLI4_MBX_EMBED); + + write_object = &mbox->u.mqe.un.write_object; + shdr = (union lpfc_sli4_cfg_shdr *)&write_object->header.cfg_shdr; + + /* Complete initializing the write object. */ + bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_Q_CREATE_VERSION_0); + bf_set(lpfc_mbx_wr_object_rlen, &write_object->u.request, datasz); + write_object->u.request.wr_object_offset = 0; + write_object->u.request.wr_object_cnt = 1; + + /* Do a byte-by-byte copy to prevent garbage data post NULL term. */ + sprintf((uint8_t *)write_object->u.request.wr_object_name, wrobject); + for (j = 0; j < strlen(wrobject); j++) + write_object->u.request.wr_object_name[j] = + cpu_to_le32(write_object->u.request.wr_object_name[j]); + + pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) { + kfree(pcmd); + mempool_free(mbox, phba->mbox_mem_pool); + return -ENOMEM; + } + + /* Clear the DMA data buffer to prevent unintended writes. Then copy + * the callers data to complete the write. + */ + memset((void *)pcmd->virt, 0, LPFC_BPL_SIZE); + write_object->u.request.wr_object_hbuf[0].pa_lo = + putPaddrLow(pcmd->phys); + write_object->u.request.wr_object_hbuf[0].pa_hi = + putPaddrHigh(pcmd->phys); + write_object->u.request.wr_object_hbuf[0].length = LPFC_BPL_SIZE; + lpfc_sli_pcimem_bcopy(datap, pcmd->virt, datasz); + + /* Caller's data is ready for FW. Terminate the data. */ + bf_set(lpfc_mbx_wr_object_eof, &write_object->u.request, 1); + + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->ctx_buf = NULL; + mbox->ctx_ndlp = NULL; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status == STATUS_FAILED && + shdr_add_status == ADD_STATUS_INVALID_OBJECT_NAME) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_CGN_MGMT, + "4675 No port cfg file in FW.\n"); + byte_cnt = -ENOENT; + } else if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2627 WRITE_OBJECT mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + byte_cnt = -ENXIO; + } else { + /* Success */ + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_CGN_MGMT, + "2628 WRITE_OBJECT Success len %d: reset %d\n", + write_object->u.response.wr_object_actual_rlen, + bf_get(lpfc_mbx_wr_object_reset, + &write_object->u.response)); + byte_cnt = write_object->u.response.wr_object_actual_rlen; + } + + lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); + kfree(pcmd); + mempool_free(mbox, phba->mbox_mem_pool); + return byte_cnt; +} + /** * lpfc_get_sgl_per_hdwq - Get one SGL chunk from hdwq's pool * @phba: The HBA for which this call is being executed. diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 7bcf922a8..eb9740449 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -95,11 +95,15 @@ struct lpfc_iocbq { #define LPFC_IO_OAS 0x10000 /* OAS FCP IO */ #define LPFC_IO_FOF 0x20000 /* FOF FCP IO */ #define LPFC_IO_LOOPBACK 0x40000 /* Loopback IO */ +#define LPFC_IO_DRVR_INIT 0x80000000 /* Driver initiated SCSI cmd */ #define LPFC_PRLI_NVME_REQ 0x80000 /* This is an NVME PRLI. */ #define LPFC_PRLI_FCP_REQ 0x100000 /* This is an NVME PRLI. */ #define LPFC_IO_NVME 0x200000 /* NVME FCP command */ #define LPFC_IO_NVME_LS 0x400000 /* NVME LS command */ #define LPFC_IO_NVMET 0x800000 /* NVMET command */ +#define LPFC_IO_RAW 0x1000000 /* Raw ELS command */ +#define LPFC_IO_CMF 0x2000000 /* CMF command */ +#define LPFC_IO_DRVR_INIT 0x80000000 uint32_t drvrTimeout; /* driver timeout in seconds */ struct lpfc_vport *vport;/* virtual port pointer */ @@ -130,6 +134,7 @@ struct lpfc_iocbq { #define IOCB_BUSY 1 #define IOCB_ERROR 2 #define IOCB_TIMEDOUT 3 +#define IOCB_ABORTED 4 #define SLI_WQE_RET_WQE 1 /* Return WQE if cmd ring full */ @@ -348,7 +353,7 @@ struct lpfc_sli { struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */ size_t iocbq_lookup_len; /* current lengs of the array */ uint16_t last_iotag; /* last allocated IOTAG */ - time64_t stats_start; /* in seconds */ + unsigned long stats_start; /* in seconds */ struct lpfc_lnk_stat lnk_stat_offsets; }; @@ -411,6 +416,10 @@ struct lpfc_io_buf { * protection data */ + void *edifp; /* External DIF information + * for IO + */ + /* * data and dma_handle are the kernel virtual and bus * address of the dma-able buffer containing the @@ -439,6 +448,7 @@ struct lpfc_io_buf { struct { struct nvmefc_fcp_req *nvmeCmd; uint16_t qidx; + }; }; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -446,6 +456,7 @@ struct lpfc_io_buf { uint64_t ts_last_cmd; uint64_t ts_cmd_wqput; uint64_t ts_isr_cmpl; - uint64_t ts_data_nvme; + uint64_t ts_data_io; #endif + uint64_t rx_cmd_start; }; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index c60a636a8..870954788 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,6 +20,9 @@ * included with this package. * *******************************************************************/ +#include +#include + #if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS) #define CONFIG_SCSI_LPFC_DEBUG_FS #endif @@ -41,10 +44,16 @@ /* Multi-queue arrangement for FCP EQ/CQ/WQ tuples */ #define LPFC_HBA_HDWQ_MIN 0 -#define LPFC_HBA_HDWQ_MAX 128 -#define LPFC_HBA_HDWQ_DEF 0 +#define LPFC_HBA_HDWQ_MAX 256 +#define LPFC_HBA_HDWQ_DEF LPFC_HBA_HDWQ_MIN + +/* irq_chann range, values */ +#define LPFC_IRQ_CHANN_MIN 0 +#define LPFC_IRQ_CHANN_MAX 256 +#define LPFC_IRQ_CHANN_DEF LPFC_IRQ_CHANN_MIN /* FCP MQ queue count limiting */ +#define LPFC_FCP_SQ_THRESHOLD 4 #define LPFC_FCP_MQ_THRESHOLD_MIN 0 #define LPFC_FCP_MQ_THRESHOLD_MAX 256 #define LPFC_FCP_MQ_THRESHOLD_DEF 8 @@ -130,6 +139,16 @@ struct lpfc_rqb { struct rqb_dmabuf *); }; +enum lpfc_poll_mode { + LPFC_QUEUE_WORK, + LPFC_IRQ_POLL +}; + +struct lpfc_idle_stat { + u64 prev_idle; + u64 prev_wall; +}; + struct lpfc_queue { struct list_head list; struct list_head wq_list; @@ -216,11 +235,14 @@ struct lpfc_queue { uint8_t q_flag; #define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */ #define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */ +#define HBA_EQ_DELAY_CHK 0x2 /* EQ is a candidate for coalescing */ #define LPFC_NVMET_CQ_NOTIFY 4 void __iomem *db_regaddr; +#ifndef BUILD_BRCMFCOE uint16_t dpp_enable; uint16_t dpp_id; void __iomem *dpp_regaddr; +#endif /* For q stats */ uint32_t q_cnt_1; @@ -259,6 +281,10 @@ struct lpfc_queue { struct lpfc_queue *assoc_qp; struct list_head _poll_list; void **q_pgs; /* array to index entries per page */ + +#define LPFC_IRQ_POLL_WEIGHT 256 + struct irq_poll iop; + enum lpfc_poll_mode poll_mode; }; struct lpfc_sli4_link { @@ -466,11 +492,17 @@ struct lpfc_hba; #define LPFC_SLI4_HANDLER_NAME_SZ 16 struct lpfc_hba_eq_hdl { uint32_t idx; + uint16_t irq; char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; struct lpfc_queue *eq; + struct cpumask aff_mask; }; +#define lpfc_get_eq_hdl(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx]) +#define lpfc_get_aff_mask(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx].aff_mask) +#define lpfc_get_irq(eqidx) (phba->sli4_hba.hba_eq_hdl[eqidx].irq) + /*BB Credit recovery value*/ struct lpfc_bbscn_params { uint32_t word0; @@ -520,6 +552,8 @@ struct lpfc_pc_sli4_params { uint32_t hdr_pp_align; uint32_t sgl_pages_max; uint32_t sgl_pp_align; + uint16_t E2E_attr; + uint8_t cmf; uint8_t cqv; uint8_t mqv; uint8_t wqv; @@ -528,6 +562,7 @@ struct lpfc_pc_sli4_params { uint8_t cqav; uint8_t wqsize; uint8_t bv1s; + uint8_t pls; #define LPFC_WQ_SZ64_SUPPORT 1 #define LPFC_WQ_SZ128_SUPPORT 2 uint8_t wqpcnt; @@ -559,11 +594,10 @@ struct lpfc_sli4_lnk_info { #define LPFC_SLI4_HANDLER_CNT (LPFC_HBA_IO_CHAN_MAX+ \ LPFC_FOF_IO_CHAN_NUM) -/* Used for IRQ vector to CPU mapping */ +/* Used for tracking CPU mapping attributes */ struct lpfc_vector_map_info { uint16_t phys_id; uint16_t core_id; - uint16_t irq; uint16_t eq; uint16_t hdwq; uint16_t flag; @@ -685,13 +719,6 @@ struct lpfc_sli4_hdw_queue { struct lpfc_lock_stat lock_conflict; #endif -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -#define LPFC_CHECK_CPU_CNT 128 - uint32_t cpucheck_rcv_io[LPFC_CHECK_CPU_CNT]; - uint32_t cpucheck_xmt_io[LPFC_CHECK_CPU_CNT]; - uint32_t cpucheck_cmpl_io[LPFC_CHECK_CPU_CNT]; -#endif - /* Per HDWQ pool resources */ struct list_head sgl_list; struct list_head cmd_rsp_buf_list; @@ -728,19 +755,37 @@ struct lpfc_sli4_hdw_queue { #define lpfc_qp_spin_lock(lock, qp, lstat) spin_lock(lock) #endif +/* This cpumask_last macro define is for internal repos only. + * (RHEL 7.*, SLES15, SLES12SP4) OSes do not have cpumask_last + * routine defined in the kernel's cpumask.h + */ +#define cpumask_last(maskp) \ + find_last_bit(cpumask_bits(maskp), nr_cpumask_bits) + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +struct lpfc_hdwq_stat { + u32 hdwq_no; + u32 rcv_io; + u32 xmt_io; + u32 cmpl_io; +}; +#endif + struct lpfc_sli4_hba { void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for - * config space registers + * PCI BAR0, config space registers */ void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for - * control registers + * PCI BAR1, control registers */ void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for - * doorbell registers + * PCI BAR2, doorbell registers */ +#ifndef BUILD_BRCMFCOE void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for * dpp registers */ +#endif union { struct { /* IF Type 0, BAR 0 PCI cfg space reg mem map */ @@ -889,8 +934,9 @@ struct lpfc_sli4_hba { struct list_head sp_queue_event; struct list_head sp_cqe_event_pool; struct list_head sp_asynce_work_queue; - struct list_head sp_fcp_xri_aborted_work_queue; + spinlock_t asynce_list_lock; /* protect sp_asynce_work_queue list */ struct list_head sp_els_xri_aborted_work_queue; + spinlock_t els_xri_abrt_list_lock; /* protect els_xri_aborted list */ struct list_head sp_unsol_work_queue; struct lpfc_sli4_link link_state; struct lpfc_sli4_lnk_info lnk_info; @@ -906,8 +952,15 @@ struct lpfc_sli4_hba { struct lpfc_vector_map_info *cpu_map; uint16_t num_possible_cpu; uint16_t num_present_cpu; + struct cpumask irq_aff_mask; uint16_t curr_disp_cpu; struct lpfc_eq_intr_info __percpu *eq_info; + + uint16_t fawwpn_in_use; /* captured FA-WWPN support state */ +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + struct lpfc_hdwq_stat __percpu *c_stat; +#endif + struct lpfc_idle_stat *idle_stat; uint32_t conf_trunk; #define lpfc_conf_trunk_port0_WORD conf_trunk #define lpfc_conf_trunk_port0_SHIFT 0 @@ -933,6 +986,8 @@ struct lpfc_sli4_hba { #define lpfc_conf_trunk_port3_nd_WORD conf_trunk #define lpfc_conf_trunk_port3_nd_SHIFT 7 #define lpfc_conf_trunk_port3_nd_MASK 0x1 + uint8_t flash_id; + uint8_t asic_rev; }; enum lpfc_sge_type { @@ -1038,6 +1093,7 @@ int lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *, int lpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp, struct lpfc_queue **drqp, struct lpfc_queue **cqp, uint32_t subtype); +void lpfc_rq_adjust_repost(struct lpfc_hba *, struct lpfc_queue *, int); int lpfc_eq_destroy(struct lpfc_hba *, struct lpfc_queue *); int lpfc_cq_destroy(struct lpfc_hba *, struct lpfc_queue *); int lpfc_mq_destroy(struct lpfc_hba *, struct lpfc_queue *); @@ -1067,8 +1123,7 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *); void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); -void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); +void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba); void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, struct lpfc_io_buf *lpfc_ncmd); @@ -1109,16 +1164,17 @@ uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *); uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba); struct sli4_hybrid_sgl *lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, - struct lpfc_io_buf *buf); + struct lpfc_io_buf *lpfc_buf); struct fcp_cmd_rsp_buf *lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, - struct lpfc_io_buf *buf); -int lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *buf); + struct lpfc_io_buf + *lpfc_buf); +int lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf); int lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, - struct lpfc_io_buf *buf); + struct lpfc_io_buf *lpfc_buf); void lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba, - struct lpfc_sli4_hdw_queue *hdwq); + struct lpfc_sli4_hdw_queue *lpfc_buf); void lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, - struct lpfc_sli4_hdw_queue *hdwq); + struct lpfc_sli4_hdw_queue *lpfc_buf); static inline void *lpfc_sli4_qe(struct lpfc_queue *q, uint16_t idx) { return q->q_pgs[idx / q->entry_cnt_per_pg] + diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index b8aae31ff..dc9ef3e52 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,8 +20,12 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.4.0.0" +#define LPFC_DRIVER_VERSION "12.8.542.34" + +#ifndef BUILD_BRCMFCOE + #define LPFC_DRIVER_NAME "lpfc" +#define LPFCMGMT_NAME "lpfcmgmt" /* Used for SLI 2/3 */ #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" @@ -32,6 +36,25 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017-2019 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2021 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." + +#else + +#define LPFC_DRIVER_NAME "brcmfcoe" +#define LPFCMGMT_NAME "brcmfcoemgmt" + +/* Used for SLI 2/3 */ +#define LPFC_SP_DRIVER_HANDLER_NAME "brcmfcoe:sp" +#define LPFC_FP_DRIVER_HANDLER_NAME "brcmfcoe:fp" + +/* Used for SLI4 */ +#define LPFC_DRIVER_HANDLER_NAME "brcmfcoe:" + +#define LPFC_MODULE_DESC "Emulex FCoE SCSI driver " \ + LPFC_DRIVER_VERSION +#define LPFC_COPYRIGHT "Copyright (C) 2017 Broadcom. All Rights Reserved. " \ + "The term \"Broadcom\" refers to Broadcom Limited " \ + "and/or its subsidiaries." +#endif diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index d0296f7cf..0df362722 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -145,7 +145,7 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { if (signal_pending(current)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1830 Signal aborted mbxCmd x%x\n", mb->mbxCommand); lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -154,7 +154,7 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) mempool_free(pmb, phba->mbox_mem_pool); return -EINTR; } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1818 VPort failed init, mbxCmd x%x " "READ_SPARM mbxStatus x%x, rc = x%x\n", mb->mbxCommand, mb->mbxStatus, rc); @@ -190,7 +190,7 @@ lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn, ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0))) return 1; - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1822 Invalid %s: %02x:%02x:%02x:%02x:" "%02x:%02x:%02x:%02x\n", name_type, @@ -284,11 +284,11 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) } if (time_after(jiffies, wait_time_max)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1835 Vport discovery quiesce failed:" - " state x%x fc_flags x%x wait msecs x%x\n", - vport->port_state, vport->fc_flag, - jiffies_to_msecs(jiffies - start_time)); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "1835 Vport discovery quiesce failed:" + " state x%x fc_flags x%x wait msecs x%x\n", + vport->port_state, vport->fc_flag, + jiffies_to_msecs(jiffies - start_time)); } int @@ -305,7 +305,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) int status; if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1808 Create VPORT failed: " "NPIV is not enabled: SLImode:%d\n", phba->sli_rev); @@ -315,7 +315,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) /* NPIV is not supported if HBA has NVME Target enabled */ if (phba->nvmet_support) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3189 Create VPORT failed: " "NPIV is not supported on NVME Target\n"); rc = VPORT_INVAL; @@ -324,7 +324,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vpi = lpfc_alloc_vpi(phba); if (vpi == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1809 Create VPORT failed: " "Max VPORTs (%d) exceeded\n", phba->max_vpi); @@ -334,7 +334,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) /* Assign an unused board number */ if ((instance = lpfc_get_instance()) < 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1810 Create VPORT failed: Cannot get " "instance number\n"); lpfc_free_vpi(phba, vpi); @@ -344,7 +344,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vport = lpfc_create_port(phba, instance, &fc_vport->dev); if (!vport) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1811 Create VPORT failed: vpi x%x\n", vpi); lpfc_free_vpi(phba, vpi); rc = VPORT_NORESOURCES; @@ -356,11 +356,11 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) if ((status = lpfc_vport_sparm(phba, vport))) { if (status == -EINTR) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1831 Create VPORT Interrupted.\n"); rc = VPORT_ERROR; } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1813 Create VPORT failed. " "Cannot get sparam\n"); rc = VPORT_NORESOURCES; @@ -378,7 +378,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") || !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1821 Create VPORT failed. " "Invalid WWN format\n"); lpfc_free_vpi(phba, vpi); @@ -388,7 +388,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) } if (!lpfc_unique_wwpn(phba, vport)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1823 Create VPORT failed. " "Duplicate WWN on HBA\n"); lpfc_free_vpi(phba, vpi); @@ -426,7 +426,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) (pport->fc_flag & FC_VFI_REGISTERED)) { rc = lpfc_sli4_init_vpi(vport); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1838 Failed to INIT_VPI on vpi %d " "status %d\n", vpi, rc); rc = VPORT_NORESOURCES; @@ -469,7 +469,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) lpfc_initial_fdisc(vport); } else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0262 No NPIV Fabric support\n"); } } else { @@ -479,7 +479,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) out: lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1825 Vport Created.\n"); + "1825 Vport Created.\n"); lpfc_host_attrib_init(lpfc_shost_from_vport(vport)); error_out: return rc; @@ -534,7 +534,7 @@ disable_vport(struct fc_vport *fc_vport) } lpfc_vport_set_state(vport, FC_VPORT_DISABLED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1826 Vport Disabled.\n"); return VPORT_OK; } @@ -575,7 +575,7 @@ enable_vport(struct fc_vport *fc_vport) lpfc_initial_fdisc(vport); } else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0264 No NPIV Fabric support\n"); } } else { @@ -583,7 +583,7 @@ enable_vport(struct fc_vport *fc_vport) } out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1827 Vport Enabled.\n"); return VPORT_OK; } @@ -609,7 +609,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) bool ns_ndlp_referenced = false; if (vport->port_type == LPFC_PHYSICAL_PORT) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1812 vport_delete failed: Cannot delete " "physical host\n"); return VPORT_ERROR; @@ -618,7 +618,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) /* If the vport is a static vport fail the deletion. */ if ((vport->vport_flag & STATIC_VPORT) && !(phba->pport->load_flag & FC_UNLOADING)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1837 vport_delete failed: Cannot delete " "static vport.\n"); return VPORT_ERROR; @@ -807,7 +807,7 @@ skip_logo: spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); spin_unlock_irq(&phba->port_list_lock); - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1828 Vport Deleted.\n"); scsi_host_put(shost); return VPORT_OK; @@ -819,7 +819,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kcalloc(phba->max_vports + 1, sizeof(struct lpfc_vport *), + vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *), GFP_KERNEL); if (vports == NULL) return NULL; @@ -828,7 +828,8 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) if (port_iterator->load_flag & FC_UNLOADING) continue; if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { - lpfc_printf_vlog(port_iterator, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(port_iterator, KERN_ERR, + LOG_TRACE_EVENT, "1801 Create vport work array FAILED: " "cannot do scsi_host_get\n"); continue; @@ -898,7 +899,8 @@ lpfc_alloc_bucket(struct lpfc_vport *vport) GFP_ATOMIC); if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0287 lpfc_alloc_bucket failed to " "allocate statistical data buffer DID " "0x%x\n", ndlp->nlp_DID); diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h index f4b8528dd..9de5bd97b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.h +++ b/drivers/scsi/lpfc/lpfc_vport.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. *