linux-stable/drivers/scsi/qla2xxx/qla_init.c

9951 lines
261 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2014 QLogic Corporation
*/
#include "qla_def.h"
#include "qla_gbl.h"
#include <linux/delay.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "qla_devtbl.h"
#ifdef CONFIG_SPARC
#include <asm/prom.h>
#endif
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
#include "qla_target.h"
/*
* QLogic ISP2x00 Hardware Support Function Prototypes.
*/
static int qla2x00_isp_firmware(scsi_qla_host_t *);
static int qla2x00_setup_chip(scsi_qla_host_t *);
static int qla2x00_fw_ready(scsi_qla_host_t *);
static int qla2x00_configure_hba(scsi_qla_host_t *);
static int qla2x00_configure_loop(scsi_qla_host_t *);
static int qla2x00_configure_local_loop(scsi_qla_host_t *);
static int qla2x00_configure_fabric(scsi_qla_host_t *);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *);
static int qla2x00_restart_isp(scsi_qla_host_t *);
static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
static void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha,
struct event_arg *ea);
static void qla24xx_handle_prli_done_event(struct scsi_qla_host *,
struct event_arg *);
static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *);
/* SRB Extensions ---------------------------------------------------------- */
void
qla2x00_sp_timeout(struct timer_list *t)
{
srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer);
struct srb_iocb *iocb;
scsi_qla_host_t *vha = sp->vha;
WARN_ON(irqs_disabled());
iocb = &sp->u.iocb_cmd;
iocb->timeout(sp);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: TMR */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
if (vha && qla2x00_isp_reg_stat(vha->hw)) {
ql_log(ql_log_info, vha, 0x9008,
"PCI/Register disconnect.\n");
qla_pci_set_eeh_busy(vha);
}
}
void qla2x00_sp_free(srb_t *sp)
{
struct srb_iocb *iocb = &sp->u.iocb_cmd;
del_timer(&iocb->timer);
qla2x00_rel_sp(sp);
}
void qla2xxx_rel_done_warning(srb_t *sp, int res)
{
WARN_ONCE(1, "Calling done() of an already freed srb %p object\n", sp);
}
void qla2xxx_rel_free_warning(srb_t *sp)
{
WARN_ONCE(1, "Calling free() of an already freed srb %p object\n", sp);
}
/* Asynchronous Login/Logout Routines -------------------------------------- */
unsigned long
qla2x00_get_async_timeout(struct scsi_qla_host *vha)
{
unsigned long tmo;
struct qla_hw_data *ha = vha->hw;
/* Firmware should use switch negotiated r_a_tov for timeout. */
tmo = ha->r_a_tov / 10 * 2;
if (IS_QLAFX00(ha)) {
tmo = FX00_DEF_RATOV * 2;
} else if (!IS_FWI2_CAPABLE(ha)) {
/*
* Except for earlier ISPs where the timeout is seeded from the
* initialization control block.
*/
tmo = ha->login_timeout;
}
return tmo;
}
static void qla24xx_abort_iocb_timeout(void *data)
{
srb_t *sp = data;
struct srb_iocb *abt = &sp->u.iocb_cmd;
struct qla_qpair *qpair = sp->qpair;
u32 handle;
unsigned long flags;
int sp_found = 0, cmdsp_found = 0;
if (sp->cmd_sp)
ql_dbg(ql_dbg_async, sp->vha, 0x507c,
"Abort timeout - cmd hdl=%x, cmd type=%x hdl=%x, type=%x\n",
sp->cmd_sp->handle, sp->cmd_sp->type,
sp->handle, sp->type);
else
ql_dbg(ql_dbg_async, sp->vha, 0x507c,
"Abort timeout 2 - hdl=%x, type=%x\n",
sp->handle, sp->type);
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) {
if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] ==
sp->cmd_sp)) {
qpair->req->outstanding_cmds[handle] = NULL;
cmdsp_found = 1;
qla_put_fw_resources(qpair, &sp->cmd_sp->iores);
}
/* removing the abort */
if (qpair->req->outstanding_cmds[handle] == sp) {
qpair->req->outstanding_cmds[handle] = NULL;
sp_found = 1;
qla_put_fw_resources(qpair, &sp->iores);
break;
}
}
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
if (cmdsp_found && sp->cmd_sp) {
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/*
* This done function should take care of
* original command ref: INIT
*/
sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
}
if (sp_found) {
abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
sp->done(sp, QLA_OS_TIMER_EXPIRED);
}
}
static void qla24xx_abort_sp_done(srb_t *sp, int res)
{
struct srb_iocb *abt = &sp->u.iocb_cmd;
srb_t *orig_sp = sp->cmd_sp;
if (orig_sp)
qla_wait_nvme_release_cmd_kref(orig_sp);
if (sp->flags & SRB_WAKEUP_ON_COMP)
complete(&abt->u.abt.comp);
else
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
{
scsi_qla_host_t *vha = cmd_sp->vha;
struct srb_iocb *abt_iocb;
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT for ABTS command */
sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport,
GFP_ATOMIC);
if (!sp)
return QLA_MEMORY_ALLOC_FAILED;
qla_vha_mark_busy(vha);
abt_iocb = &sp->u.iocb_cmd;
sp->type = SRB_ABT_CMD;
sp->name = "abort";
sp->qpair = cmd_sp->qpair;
sp->cmd_sp = cmd_sp;
if (wait)
sp->flags = SRB_WAKEUP_ON_COMP;
init_completion(&abt_iocb->u.abt.comp);
/* FW can send 2 x ABTS's timeout/20s */
qla2x00_init_async_sp(sp, 42, qla24xx_abort_sp_done);
sp->u.iocb_cmd.timeout = qla24xx_abort_iocb_timeout;
abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id);
ql_dbg(ql_dbg_async, vha, 0x507c,
"Abort command issued - hdl=%x, type=%x\n", cmd_sp->handle,
cmd_sp->type);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
return rval;
}
if (wait) {
wait_for_completion(&abt_iocb->u.abt.comp);
rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
QLA_SUCCESS : QLA_ERR_FROM_FW;
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
return rval;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
void
qla2x00_async_iocb_timeout(void *data)
{
srb_t *sp = data;
fc_port_t *fcport = sp->fcport;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
struct srb_iocb *lio = &sp->u.iocb_cmd;
int rc, h;
unsigned long flags;
if (fcport) {
ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
"Async-%s timeout - hdl=%x portid=%06x %8phC.\n",
sp->name, sp->handle, fcport->d_id.b24, fcport->port_name);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
} else {
pr_info("Async-%s timeout - hdl=%x.\n",
sp->name, sp->handle);
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
switch (sp->type) {
case SRB_LOGIN_CMD:
rc = qla24xx_async_abort_cmd(sp, false);
if (rc) {
/* Retry as needed. */
lio->u.logio.data[0] = MBS_COMMAND_ERROR;
lio->u.logio.data[1] =
lio->u.logio.flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED : 0;
spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
for (h = 1; h < sp->qpair->req->num_outstanding_cmds;
h++) {
if (sp->qpair->req->outstanding_cmds[h] ==
sp) {
sp->qpair->req->outstanding_cmds[h] =
NULL;
break;
}
}
spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
sp->done(sp, QLA_FUNCTION_TIMEOUT);
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
case SRB_LOGOUT_CMD:
case SRB_CT_PTHRU_CMD:
case SRB_MB_IOCB:
case SRB_NACK_PLOGI:
case SRB_NACK_PRLI:
case SRB_NACK_LOGO:
case SRB_CTRL_VP:
default:
rc = qla24xx_async_abort_cmd(sp, false);
if (rc) {
spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
for (h = 1; h < sp->qpair->req->num_outstanding_cmds;
h++) {
if (sp->qpair->req->outstanding_cmds[h] ==
sp) {
sp->qpair->req->outstanding_cmds[h] =
NULL;
break;
}
}
spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
sp->done(sp, QLA_FUNCTION_TIMEOUT);
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
}
}
static void qla2x00_async_login_sp_done(srb_t *sp, int res)
{
struct scsi_qla_host *vha = sp->vha;
struct srb_iocb *lio = &sp->u.iocb_cmd;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
struct event_arg ea;
ql_dbg(ql_dbg_disc, vha, 0x20dd,
"%s %8phC res %d \n", __func__, sp->fcport->port_name, res);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (!test_bit(UNLOADING, &vha->dpc_flags)) {
memset(&ea, 0, sizeof(ea));
ea.fcport = sp->fcport;
ea.data[0] = lio->u.logio.data[0];
ea.data[1] = lio->u.logio.data[1];
ea.iop[0] = lio->u.logio.iop[0];
ea.iop[1] = lio->u.logio.iop[1];
ea.sp = sp;
scsi: qla2xxx: Fix warning message due to adisc being flushed Fix warning message due to adisc being flushed. Linux kernel triggered a warning message where a different error code type is not matching up with the expected type. Add additional translation of one error code type to another. WARNING: CPU: 2 PID: 1131623 at drivers/scsi/qla2xxx/qla_init.c:498 qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] CPU: 2 PID: 1131623 Comm: drmgr Not tainted 5.13.0-rc1-autotest #1 .. GPR28: c000000aaa9c8890 c0080000079ab678 c00000140a104800 c00000002bd19000 NIP [c00800000790857c] qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] LR [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] Call Trace: [c00000001cdc3620] [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] (unreliable) [c00000001cdc3710] [c0080000078f3080] __qla2x00_abort_all_cmds+0x1b8/0x580 [qla2xxx] [c00000001cdc3840] [c0080000078f589c] qla2x00_abort_all_cmds+0x34/0xd0 [qla2xxx] [c00000001cdc3880] [c0080000079153d8] qla2x00_abort_isp_cleanup+0x3f0/0x570 [qla2xxx] [c00000001cdc3920] [c0080000078fb7e8] qla2x00_remove_one+0x3d0/0x480 [qla2xxx] [c00000001cdc39b0] [c00000000071c274] pci_device_remove+0x64/0x120 [c00000001cdc39f0] [c0000000007fb818] device_release_driver_internal+0x168/0x2a0 [c00000001cdc3a30] [c00000000070e304] pci_stop_bus_device+0xb4/0x100 [c00000001cdc3a70] [c00000000070e4f0] pci_stop_and_remove_bus_device+0x20/0x40 [c00000001cdc3aa0] [c000000000073940] pci_hp_remove_devices+0x90/0x130 [c00000001cdc3b30] [c0080000070704d0] disable_slot+0x38/0x90 [rpaphp] [ c00000001cdc3b60] [c00000000073eb4c] power_write_file+0xcc/0x180 [c00000001cdc3be0] [c0000000007354bc] pci_slot_attr_store+0x3c/0x60 [c00000001cdc3c00] [c00000000055f820] sysfs_kf_write+0x60/0x80 [c00000001cdc3c20] [c00000000055df10] kernfs_fop_write_iter+0x1a0/0x290 [c00000001cdc3c70] [c000000000447c4c] new_sync_write+0x14c/0x1d0 [c00000001cdc3d10] [c00000000044b134] vfs_write+0x224/0x330 [c00000001cdc3d60] [c00000000044b3f4] ksys_write+0x74/0x130 [c00000001cdc3db0] [c00000000002df70] system_call_exception+0x150/0x2d0 [c00000001cdc3e10] [c00000000000d45c] system_call_common+0xec/0x278 Link: https://lore.kernel.org/r/20220110050218.3958-5-njavali@marvell.com Cc: stable@vger.kernel.org Reported-by: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:05 +00:00
if (res)
ea.data[0] = MBS_COMMAND_ERROR;
qla24xx_handle_plogi_done_event(vha, &ea);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
srb_t *sp;
struct srb_iocb *lio;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
int rval = QLA_FUNCTION_FAILED;
if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) ||
fcport->loop_id == FC_NO_LOOP_ID) {
ql_log(ql_log_warn, vha, 0xffff,
"%s: %8phC - not sending command.\n",
__func__, fcport->port_name);
return rval;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_PEND);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->flags |= FCF_ASYNC_SENT;
fcport->logout_completed = 0;
sp->type = SRB_LOGIN_CMD;
sp->name = "login";
sp->gen1 = fcport->rscn_gen;
sp->gen2 = fcport->login_gen;
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla2x00_async_login_sp_done);
lio = &sp->u.iocb_cmd;
if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) {
lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY;
} else {
if (vha->hw->flags.edif_enabled &&
DBELL_ACTIVE(vha)) {
lio->u.logio.flags |=
(SRB_LOGIN_FCSP | SRB_LOGIN_SKIP_PRLI);
} else {
lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
}
}
if (NVME_TARGET(vha->hw, fcport))
lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
rval = qla2x00_start_sp(sp);
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n",
fcport->port_name, sp->handle, fcport->loop_id,
fcport->d_id.b24, fcport->login_retry,
lio->u.logio.flags & SRB_LOGIN_FCSP ? "FCSP" : "");
if (rval != QLA_SUCCESS) {
fcport->flags |= FCF_LOGIN_NEEDED;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
goto done_free_sp;
}
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->flags &= ~FCF_ASYNC_SENT;
done:
fcport->flags &= ~FCF_ASYNC_ACTIVE;
/*
* async login failed. Could be due to iocb/exchange resource
* being low. Set state DELETED for re-login process to start again.
*/
qla2x00_set_fcport_disc_state(fcport, DSC_DELETED);
return rval;
}
static void qla2x00_async_logout_sp_done(srb_t *sp, int res)
{
sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
scsi: qla2xxx: Fix double free bug after firmware timeout This patch is based on Max's original patch. When the qla2xxx firmware is unavailable, eventually qla2x00_sp_timeout() is reached, which calls the timeout function and frees the srb_t instance. The timeout function always resolves to qla2x00_async_iocb_timeout(), which invokes another callback function called "done". All of these qla2x00_*_sp_done() callbacks also free the srb_t instance; after returning to qla2x00_sp_timeout(), it is freed again. The fix is to remove the "sp->free(sp)" call from qla2x00_sp_timeout() and add it to those code paths in qla2x00_async_iocb_timeout() which do not already free the object. This is how it looks like with KASAN: BUG: KASAN: use-after-free in qla2x00_sp_timeout+0x228/0x250 Read of size 8 at addr ffff88278147a590 by task swapper/2/0 Allocated by task 1502: save_stack+0x33/0xa0 kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc+0xb8/0x1c0 mempool_alloc+0xd6/0x260 qla24xx_async_gnl+0x3c5/0x1100 Freed by task 0: save_stack+0x33/0xa0 kasan_slab_free+0x72/0xc0 kmem_cache_free+0x75/0x200 qla24xx_async_gnl_sp_done+0x556/0x9e0 qla2x00_async_iocb_timeout+0x1c7/0x420 qla2x00_sp_timeout+0x16d/0x250 call_timer_fn+0x36/0x200 The buggy address belongs to the object at ffff88278147a440 which belongs to the cache qla2xxx_srbs of size 344 The buggy address is located 336 bytes inside of 344-byte region [ffff88278147a440, ffff88278147a598) Reported-by: Max Kellermann <mk@cm4all.com> Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> Cc: Max Kellermann <mk@cm4all.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2018-02-01 18:33:17 +00:00
sp->fcport->login_gen++;
qlt_logo_completion_handler(sp->fcport, sp->u.iocb_cmd.u.logio.data[0]);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->flags |= FCF_ASYNC_SENT;
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
sp->type = SRB_LOGOUT_CMD;
sp->name = "logout";
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla2x00_async_logout_sp_done),
ql_dbg(ql_dbg_disc, vha, 0x2070,
"Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x %8phC explicit %d.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->port_name, fcport->explicit_logout);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
return rval;
}
void
qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
fcport->flags &= ~FCF_ASYNC_ACTIVE;
/* Don't re-login in target mode */
if (!fcport->tgt_session)
qla2x00_mark_device_lost(vha, fcport, 1);
qlt_logo_completion_handler(fcport, data[0]);
}
static void qla2x00_async_prlo_sp_done(srb_t *sp, int res)
{
struct srb_iocb *lio = &sp->u.iocb_cmd;
struct scsi_qla_host *vha = sp->vha;
sp->fcport->flags &= ~FCF_ASYNC_ACTIVE;
if (!test_bit(UNLOADING, &vha->dpc_flags))
qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport,
lio->u.logio.data);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int
qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
{
srb_t *sp;
int rval;
rval = QLA_FUNCTION_FAILED;
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
sp->type = SRB_PRLO_CMD;
sp->name = "prlo";
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla2x00_async_prlo_sp_done);
ql_dbg(ql_dbg_disc, vha, 0x2070,
"Async-prlo - hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
fcport->flags &= ~FCF_ASYNC_ACTIVE;
return rval;
}
static
void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
{
struct fc_port *fcport = ea->fcport;
ql_dbg(ql_dbg_disc, vha, 0x20d2,
"%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2,
fcport->rscn_gen, ea->sp->gen1, fcport->loop_id);
WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n",
ea->data[0]);
if (ea->data[0] != MBS_COMMAND_COMPLETE) {
ql_dbg(ql_dbg_disc, vha, 0x2066,
"%s %8phC: adisc fail: post delete\n",
__func__, ea->fcport->port_name);
/* deleted = 0 & logout_on_delete = force fw cleanup */
fcport->deleted = 0;
fcport->logout_on_delete = 1;
qlt_schedule_sess_for_deletion(ea->fcport);
return;
}
if (ea->fcport->disc_state == DSC_DELETE_PEND)
return;
if (ea->sp->gen2 != ea->fcport->login_gen) {
/* target side must have changed it. */
ql_dbg(ql_dbg_disc, vha, 0x20d3,
"%s %8phC generation changed\n",
__func__, ea->fcport->port_name);
return;
} else if (ea->sp->gen1 != ea->fcport->rscn_gen) {
qla_rscn_replay(fcport);
qlt_schedule_sess_for_deletion(fcport);
return;
}
__qla24xx_handle_gpdb_event(vha, ea);
}
static int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_ELS_PLOGI);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
fcport->flags |= FCF_ASYNC_ACTIVE;
qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_PEND);
return qla2x00_post_work(vha, e);
}
static void qla2x00_async_adisc_sp_done(srb_t *sp, int res)
{
struct scsi_qla_host *vha = sp->vha;
struct event_arg ea;
struct srb_iocb *lio = &sp->u.iocb_cmd;
ql_dbg(ql_dbg_disc, vha, 0x2066,
"Async done-%s res %x %8phC\n",
sp->name, res, sp->fcport->port_name);
sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
memset(&ea, 0, sizeof(ea));
ea.rc = res;
ea.data[0] = lio->u.logio.data[0];
ea.data[1] = lio->u.logio.data[1];
ea.iop[0] = lio->u.logio.iop[0];
ea.iop[1] = lio->u.logio.iop[1];
ea.fcport = sp->fcport;
ea.sp = sp;
scsi: qla2xxx: Fix warning message due to adisc being flushed Fix warning message due to adisc being flushed. Linux kernel triggered a warning message where a different error code type is not matching up with the expected type. Add additional translation of one error code type to another. WARNING: CPU: 2 PID: 1131623 at drivers/scsi/qla2xxx/qla_init.c:498 qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] CPU: 2 PID: 1131623 Comm: drmgr Not tainted 5.13.0-rc1-autotest #1 .. GPR28: c000000aaa9c8890 c0080000079ab678 c00000140a104800 c00000002bd19000 NIP [c00800000790857c] qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] LR [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] Call Trace: [c00000001cdc3620] [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] (unreliable) [c00000001cdc3710] [c0080000078f3080] __qla2x00_abort_all_cmds+0x1b8/0x580 [qla2xxx] [c00000001cdc3840] [c0080000078f589c] qla2x00_abort_all_cmds+0x34/0xd0 [qla2xxx] [c00000001cdc3880] [c0080000079153d8] qla2x00_abort_isp_cleanup+0x3f0/0x570 [qla2xxx] [c00000001cdc3920] [c0080000078fb7e8] qla2x00_remove_one+0x3d0/0x480 [qla2xxx] [c00000001cdc39b0] [c00000000071c274] pci_device_remove+0x64/0x120 [c00000001cdc39f0] [c0000000007fb818] device_release_driver_internal+0x168/0x2a0 [c00000001cdc3a30] [c00000000070e304] pci_stop_bus_device+0xb4/0x100 [c00000001cdc3a70] [c00000000070e4f0] pci_stop_and_remove_bus_device+0x20/0x40 [c00000001cdc3aa0] [c000000000073940] pci_hp_remove_devices+0x90/0x130 [c00000001cdc3b30] [c0080000070704d0] disable_slot+0x38/0x90 [rpaphp] [ c00000001cdc3b60] [c00000000073eb4c] power_write_file+0xcc/0x180 [c00000001cdc3be0] [c0000000007354bc] pci_slot_attr_store+0x3c/0x60 [c00000001cdc3c00] [c00000000055f820] sysfs_kf_write+0x60/0x80 [c00000001cdc3c20] [c00000000055df10] kernfs_fop_write_iter+0x1a0/0x290 [c00000001cdc3c70] [c000000000447c4c] new_sync_write+0x14c/0x1d0 [c00000001cdc3d10] [c00000000044b134] vfs_write+0x224/0x330 [c00000001cdc3d60] [c00000000044b3f4] ksys_write+0x74/0x130 [c00000001cdc3db0] [c00000000002df70] system_call_exception+0x150/0x2d0 [c00000001cdc3e10] [c00000000000d45c] system_call_common+0xec/0x278 Link: https://lore.kernel.org/r/20220110050218.3958-5-njavali@marvell.com Cc: stable@vger.kernel.org Reported-by: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:05 +00:00
if (res)
ea.data[0] = MBS_COMMAND_ERROR;
qla24xx_handle_adisc_event(vha, &ea);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int
qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
srb_t *sp;
struct srb_iocb *lio;
int rval = QLA_FUNCTION_FAILED;
if (IS_SESSION_DELETED(fcport)) {
ql_log(ql_log_warn, vha, 0xffff,
"%s: %8phC is being delete - not sending command.\n",
__func__, fcport->port_name);
fcport->flags &= ~FCF_ASYNC_ACTIVE;
return rval;
}
if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
return rval;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->flags |= FCF_ASYNC_SENT;
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
sp->type = SRB_ADISC_CMD;
sp->name = "adisc";
sp->gen1 = fcport->rscn_gen;
sp->gen2 = fcport->login_gen;
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla2x00_async_adisc_sp_done);
if (data[1] & QLA_LOGIO_LOGIN_RETRIED) {
lio = &sp->u.iocb_cmd;
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
}
ql_dbg(ql_dbg_disc, vha, 0x206f,
"Async-adisc - hdl=%x loopid=%x portid=%06x %8phC.\n",
sp->handle, fcport->loop_id, fcport->d_id.b24, fcport->port_name);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
qla2x00_post_async_adisc_work(vha, fcport, data);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return rval;
}
static bool qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
{
struct qla_hw_data *ha = vha->hw;
if (IS_FWI2_CAPABLE(ha))
return loop_id > NPH_LAST_HANDLE;
return (loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST;
}
/**
* qla2x00_find_new_loop_id - scan through our port list and find a new usable loop ID
* @vha: adapter state pointer.
* @dev: port structure pointer.
*
* Returns:
* qla2x00 local function return status code.
*
* Context:
* Kernel context.
*/
static int qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
{
int rval;
struct qla_hw_data *ha = vha->hw;
unsigned long flags = 0;
rval = QLA_SUCCESS;
spin_lock_irqsave(&ha->vport_slock, flags);
dev->loop_id = find_first_zero_bit(ha->loop_id_map, LOOPID_MAP_SIZE);
if (dev->loop_id >= LOOPID_MAP_SIZE ||
qla2x00_is_reserved_id(vha, dev->loop_id)) {
dev->loop_id = FC_NO_LOOP_ID;
rval = QLA_FUNCTION_FAILED;
} else {
set_bit(dev->loop_id, ha->loop_id_map);
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
if (rval == QLA_SUCCESS)
ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
"Assigning new loopid=%x, portid=%x.\n",
dev->loop_id, dev->d_id.b24);
else
ql_log(ql_log_warn, dev->vha, 0x2087,
"No loop_id's available, portid=%x.\n",
dev->d_id.b24);
return rval;
}
void qla2x00_clear_loop_id(fc_port_t *fcport)
{
struct qla_hw_data *ha = fcport->vha->hw;
if (fcport->loop_id == FC_NO_LOOP_ID ||
qla2x00_is_reserved_id(fcport->vha, fcport->loop_id))
return;
clear_bit(fcport->loop_id, ha->loop_id_map);
fcport->loop_id = FC_NO_LOOP_ID;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
struct event_arg *ea)
{
fc_port_t *fcport, *conflict_fcport;
struct get_name_list_extended *e;
u16 i, n, found = 0, loop_id;
port_id_t id;
u64 wwn;
u16 data[2];
u8 current_login_state, nvme_cls;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport = ea->fcport;
ql_dbg(ql_dbg_disc, vha, 0xffff,
"%s %8phC DS %d LS rc %d %d login %d|%d rscn %d|%d lid %d edif %d\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, ea->rc,
fcport->login_gen, fcport->last_login_gen,
fcport->rscn_gen, fcport->last_rscn_gen, vha->loop_id, fcport->edif.enable);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (fcport->disc_state == DSC_DELETE_PEND)
return;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (ea->rc) { /* rval */
if (fcport->login_retry == 0) {
ql_dbg(ql_dbg_disc, vha, 0x20de,
"GNL failed Port login retry %8phN, retry cnt=%d.\n",
fcport->port_name, fcport->login_retry);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
return;
}
if (fcport->last_rscn_gen != fcport->rscn_gen) {
qla_rscn_replay(fcport);
qlt_schedule_sess_for_deletion(fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return;
} else if (fcport->last_login_gen != fcport->login_gen) {
ql_dbg(ql_dbg_disc, vha, 0x20e0,
"%s %8phC login gen changed\n",
__func__, fcport->port_name);
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return;
}
n = ea->data[0] / sizeof(struct get_name_list_extended);
ql_dbg(ql_dbg_disc, vha, 0x20e1,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"%s %d %8phC n %d %02x%02x%02x lid %d \n",
__func__, __LINE__, fcport->port_name, n,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, fcport->loop_id);
for (i = 0; i < n; i++) {
e = &vha->gnl.l[i];
wwn = wwn_to_u64(e->port_name);
id.b.domain = e->port_id[2];
id.b.area = e->port_id[1];
id.b.al_pa = e->port_id[0];
id.b.rsvd_1 = 0;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE))
continue;
if (IS_SW_RESV_ADDR(id))
continue;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
found = 1;
loop_id = le16_to_cpu(e->nport_handle);
loop_id = (loop_id & 0x7fff);
nvme_cls = e->current_login_state >> 4;
current_login_state = e->current_login_state & 0xf;
if (PRLI_PHASE(nvme_cls)) {
current_login_state = nvme_cls;
fcport->fc4_type &= ~FS_FC4TYPE_FCP;
fcport->fc4_type |= FS_FC4TYPE_NVME;
} else if (PRLI_PHASE(current_login_state)) {
fcport->fc4_type |= FS_FC4TYPE_FCP;
fcport->fc4_type &= ~FS_FC4TYPE_NVME;
}
ql_dbg(ql_dbg_disc, vha, 0x20e2,
"%s found %8phC CLS [%x|%x] fc4_type %d ID[%06x|%06x] lid[%d|%d]\n",
__func__, fcport->port_name,
e->current_login_state, fcport->fw_login_state,
fcport->fc4_type, id.b24, fcport->d_id.b24,
loop_id, fcport->loop_id);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
switch (fcport->disc_state) {
case DSC_DELETE_PEND:
case DSC_DELETED:
break;
default:
if ((id.b24 != fcport->d_id.b24 &&
fcport->d_id.b24 &&
fcport->loop_id != FC_NO_LOOP_ID) ||
(fcport->loop_id != FC_NO_LOOP_ID &&
fcport->loop_id != loop_id)) {
ql_dbg(ql_dbg_disc, vha, 0x20e3,
"%s %d %8phC post del sess\n",
__func__, __LINE__, fcport->port_name);
if (fcport->n2n_flag)
fcport->d_id.b24 = 0;
qlt_schedule_sess_for_deletion(fcport);
return;
}
break;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
fcport->loop_id = loop_id;
if (fcport->n2n_flag)
fcport->d_id.b24 = id.b24;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
wwn = wwn_to_u64(fcport->port_name);
qlt_find_sess_invalidate_other(vha, wwn,
id, loop_id, &conflict_fcport);
if (conflict_fcport) {
/*
* Another share fcport share the same loop_id &
* nport id. Conflict fcport needs to finish
* cleanup before this fcport can proceed to login.
*/
conflict_fcport->conflict = fcport;
fcport->login_pause = 1;
}
switch (vha->hw->current_topology) {
default:
switch (current_login_state) {
case DSC_LS_PRLI_COMP:
ql_dbg(ql_dbg_disc,
vha, 0x20e4, "%s %d %8phC post gpdb\n",
__func__, __LINE__, fcport->port_name);
if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
data[0] = data[1] = 0;
qla2x00_post_async_adisc_work(vha, fcport,
data);
break;
case DSC_LS_PLOGI_COMP:
if (vha->hw->flags.edif_enabled) {
/* check to see if App support Secure */
qla24xx_post_gpdb_work(vha, fcport, 0);
break;
}
fallthrough;
case DSC_LS_PORT_UNAVAIL:
default:
if (fcport->loop_id == FC_NO_LOOP_ID) {
qla2x00_find_new_loop_id(vha, fcport);
fcport->fw_login_state =
DSC_LS_PORT_UNAVAIL;
}
ql_dbg(ql_dbg_disc, vha, 0x20e5,
"%s %d %8phC\n", __func__, __LINE__,
fcport->port_name);
qla24xx_fcport_handle_login(vha, fcport);
break;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
break;
case ISP_CFG_N:
fcport->fw_login_state = current_login_state;
fcport->d_id = id;
switch (current_login_state) {
case DSC_LS_PRLI_PEND:
/*
* In the middle of PRLI. Let it finish.
* Allow relogin code to recheck state again
* with GNL. Push disc_state back to DELETED
* so GNL can go out again
*/
qla2x00_set_fcport_disc_state(fcport,
DSC_DELETED);
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
break;
case DSC_LS_PRLI_COMP:
if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
data[0] = data[1] = 0;
qla2x00_post_async_adisc_work(vha, fcport,
data);
break;
case DSC_LS_PLOGI_COMP:
if (vha->hw->flags.edif_enabled &&
DBELL_ACTIVE(vha)) {
/* check to see if App support secure or not */
qla24xx_post_gpdb_work(vha, fcport, 0);
break;
}
if (fcport_is_bigger(fcport)) {
/* local adapter is smaller */
if (fcport->loop_id != FC_NO_LOOP_ID)
qla2x00_clear_loop_id(fcport);
fcport->loop_id = loop_id;
qla24xx_fcport_handle_login(vha,
fcport);
break;
}
fallthrough;
default:
if (fcport_is_smaller(fcport)) {
/* local adapter is bigger */
if (fcport->loop_id != FC_NO_LOOP_ID)
qla2x00_clear_loop_id(fcport);
fcport->loop_id = loop_id;
qla24xx_fcport_handle_login(vha,
fcport);
}
break;
}
break;
} /* switch (ha->current_topology) */
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
if (!found) {
switch (vha->hw->current_topology) {
case ISP_CFG_F:
case ISP_CFG_FL:
for (i = 0; i < n; i++) {
e = &vha->gnl.l[i];
id.b.domain = e->port_id[0];
id.b.area = e->port_id[1];
id.b.al_pa = e->port_id[2];
id.b.rsvd_1 = 0;
loop_id = le16_to_cpu(e->nport_handle);
if (fcport->d_id.b24 == id.b24) {
conflict_fcport =
qla2x00_find_fcport_by_wwpn(vha,
e->port_name, 0);
SCSI misc on 20180815 This is mostly updates to the usual drivers: mpt3sas, lpfc, qla2xxx, hisi_sas, smartpqi, megaraid_sas, arcmsr. In addition, with the continuing absence of Nic we have target updates for tcmu and target core (all with reviews and acks). The biggest observable change is going to be that we're (again) trying to switch to mulitqueue as the default (a user can still override the setting on the kernel command line). Other major core stuff is the removal of the remaining Microchannel drivers, an update of the internal timers and some reworks of completion and result handling. Signed-off-by: James E.J. Bottomley <jejb@linux.vnet.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCW3R3niYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishauRAP4yfBKK dbxF81c/Bxi/Stk16FWkOOrjs4CizwmnMcpM5wD/UmM9o6ebDzaYpZgA8wIl7X/N o/JckEZZpIp+5NySZNc= =ggLB -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI updates from James Bottomley: "This is mostly updates to the usual drivers: mpt3sas, lpfc, qla2xxx, hisi_sas, smartpqi, megaraid_sas, arcmsr. In addition, with the continuing absence of Nic we have target updates for tcmu and target core (all with reviews and acks). The biggest observable change is going to be that we're (again) trying to switch to mulitqueue as the default (a user can still override the setting on the kernel command line). Other major core stuff is the removal of the remaining Microchannel drivers, an update of the internal timers and some reworks of completion and result handling" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (203 commits) scsi: core: use blk_mq_run_hw_queues in scsi_kick_queue scsi: ufs: remove unnecessary query(DM) UPIU trace scsi: qla2xxx: Fix issue reported by static checker for qla2x00_els_dcmd2_sp_done() scsi: aacraid: Spelling fix in comment scsi: mpt3sas: Fix calltrace observed while running IO & reset scsi: aic94xx: fix an error code in aic94xx_init() scsi: st: remove redundant pointer STbuffer scsi: qla2xxx: Update driver version to 10.00.00.08-k scsi: qla2xxx: Migrate NVME N2N handling into state machine scsi: qla2xxx: Save frame payload size from ICB scsi: qla2xxx: Fix stalled relogin scsi: qla2xxx: Fix race between switch cmd completion and timeout scsi: qla2xxx: Fix Management Server NPort handle reservation logic scsi: qla2xxx: Flush mailbox commands on chip reset scsi: qla2xxx: Fix unintended Logout scsi: qla2xxx: Fix session state stuck in Get Port DB scsi: qla2xxx: Fix redundant fc_rport registration scsi: qla2xxx: Silent erroneous message scsi: qla2xxx: Prevent sysfs access when chip is down scsi: qla2xxx: Add longer window for chip reset ...
2018-08-16 05:06:26 +00:00
if (conflict_fcport) {
ql_dbg(ql_dbg_disc + ql_dbg_verbose,
vha, 0x20e5,
"%s %d %8phC post del sess\n",
__func__, __LINE__,
conflict_fcport->port_name);
qlt_schedule_sess_for_deletion
(conflict_fcport);
}
scsi: qla2xxx: Fix NULL pointer dereference for fcport search Crash dump shows following instructions crash> bt PID: 0 TASK: ffffffffbe412480 CPU: 0 COMMAND: "swapper/0" #0 [ffff891ee0003868] machine_kexec at ffffffffbd063ef1 #1 [ffff891ee00038c8] __crash_kexec at ffffffffbd12b6f2 #2 [ffff891ee0003998] crash_kexec at ffffffffbd12c84c #3 [ffff891ee00039b8] oops_end at ffffffffbd030f0a #4 [ffff891ee00039e0] no_context at ffffffffbd074643 #5 [ffff891ee0003a40] __bad_area_nosemaphore at ffffffffbd07496e #6 [ffff891ee0003a90] bad_area_nosemaphore at ffffffffbd074a64 #7 [ffff891ee0003aa0] __do_page_fault at ffffffffbd074b0a #8 [ffff891ee0003b18] do_page_fault at ffffffffbd074fc8 #9 [ffff891ee0003b50] page_fault at ffffffffbda01925 [exception RIP: qlt_schedule_sess_for_deletion+15] RIP: ffffffffc02e526f RSP: ffff891ee0003c08 RFLAGS: 00010046 RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffffffffc0307847 RDX: 00000000000020e6 RSI: ffff891edbc377c8 RDI: 0000000000000000 RBP: ffff891ee0003c18 R8: ffffffffc02f0b20 R9: 0000000000000250 R10: 0000000000000258 R11: 000000000000b780 R12: ffff891ed9b43000 R13: 00000000000000f0 R14: 0000000000000006 R15: ffff891edbc377c8 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #10 [ffff891ee0003c20] qla2x00_fcport_event_handler at ffffffffc02853d3 [qla2xxx] #11 [ffff891ee0003cf0] __dta_qla24xx_async_gnl_sp_done_333 at ffffffffc0285a1d [qla2xxx] #12 [ffff891ee0003de8] qla24xx_process_response_queue at ffffffffc02a2eb5 [qla2xxx] #13 [ffff891ee0003e88] qla24xx_msix_rsp_q at ffffffffc02a5403 [qla2xxx] #14 [ffff891ee0003ec0] __handle_irq_event_percpu at ffffffffbd0f4c59 #15 [ffff891ee0003f10] handle_irq_event_percpu at ffffffffbd0f4e02 #16 [ffff891ee0003f40] handle_irq_event at ffffffffbd0f4e90 #17 [ffff891ee0003f68] handle_edge_irq at ffffffffbd0f8984 #18 [ffff891ee0003f88] handle_irq at ffffffffbd0305d5 #19 [ffff891ee0003fb8] do_IRQ at ffffffffbda02a18 --- <IRQ stack> --- #20 [ffffffffbe403d30] ret_from_intr at ffffffffbda0094e [exception RIP: unknown or invalid address] RIP: 000000000000001f RSP: 0000000000000000 RFLAGS: fff3b8c2091ebb3f RAX: ffffbba5a0000200 RBX: 0000be8cdfa8f9fa RCX: 0000000000000018 RDX: 0000000000000101 RSI: 000000000000015d RDI: 0000000000000193 RBP: 0000000000000083 R8: ffffffffbe403e38 R9: 0000000000000002 R10: 0000000000000000 R11: ffffffffbe56b820 R12: ffff891ee001cf00 R13: ffffffffbd11c0a4 R14: ffffffffbe403d60 R15: 0000000000000001 ORIG_RAX: ffff891ee0022ac0 CS: 0000 SS: ffffffffffffffb9 bt: WARNING: possibly bogus exception frame #21 [ffffffffbe403dd8] cpuidle_enter_state at ffffffffbd67c6fd #22 [ffffffffbe403e40] cpuidle_enter at ffffffffbd67c907 #23 [ffffffffbe403e50] call_cpuidle at ffffffffbd0d98f3 #24 [ffffffffbe403e60] do_idle at ffffffffbd0d9b42 #25 [ffffffffbe403e98] cpu_startup_entry at ffffffffbd0d9da3 #26 [ffffffffbe403ec0] rest_init at ffffffffbd81d4aa #27 [ffffffffbe403ed0] start_kernel at ffffffffbe67d2ca #28 [ffffffffbe403f28] x86_64_start_reservations at ffffffffbe67c675 #29 [ffffffffbe403f38] x86_64_start_kernel at ffffffffbe67c6eb #30 [ffffffffbe403f50] secondary_startup_64 at ffffffffbd0000d5 Fixes: 040036bb0bc1 ("scsi: qla2xxx: Delay loop id allocation at login") Cc: <stable@vger.kernel.org> # v4.17+ Signed-off-by: Chuck Anderson <chuck.anderson@oracle.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2018-07-02 20:02:00 +00:00
}
/*
* FW already picked this loop id for
* another fcport
*/
if (fcport->loop_id == loop_id)
fcport->loop_id = FC_NO_LOOP_ID;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
qla24xx_fcport_handle_login(vha, fcport);
break;
case ISP_CFG_N:
qla2x00_set_fcport_disc_state(fcport, DSC_DELETED);
if (time_after_eq(jiffies, fcport->dm_login_expire)) {
if (fcport->n2n_link_reset_cnt < 2) {
fcport->n2n_link_reset_cnt++;
/*
* remote port is not sending PLOGI.
* Reset link to kick start his state
* machine
*/
set_bit(N2N_LINK_RESET,
&vha->dpc_flags);
} else {
if (fcport->n2n_chip_reset < 1) {
ql_log(ql_log_info, vha, 0x705d,
"Chip reset to bring laser down");
set_bit(ISP_ABORT_NEEDED,
&vha->dpc_flags);
fcport->n2n_chip_reset++;
} else {
ql_log(ql_log_info, vha, 0x705d,
"Remote port %8ph is not coming back\n",
fcport->port_name);
fcport->scan_state = 0;
}
}
qla2xxx_wake_dpc(vha);
} else {
/*
* report port suppose to do PLOGI. Give him
* more time. FW will catch it.
*/
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
}
break;
case ISP_CFG_NL:
qla24xx_fcport_handle_login(vha, fcport);
break;
default:
break;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
}
} /* gnl_event */
static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
{
struct scsi_qla_host *vha = sp->vha;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
unsigned long flags;
struct fc_port *fcport = NULL, *tf;
u16 i, n = 0, loop_id;
struct event_arg ea;
struct get_name_list_extended *e;
u64 wwn;
struct list_head h;
bool found = false;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
ql_dbg(ql_dbg_disc, vha, 0x20e7,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"Async done-%s res %x mb[1]=%x mb[2]=%x \n",
sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1],
sp->u.iocb_cmd.u.mbx.in_mb[2]);
sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
memset(&ea, 0, sizeof(ea));
ea.sp = sp;
ea.rc = res;
if (sp->u.iocb_cmd.u.mbx.in_mb[1] >=
sizeof(struct get_name_list_extended)) {
n = sp->u.iocb_cmd.u.mbx.in_mb[1] /
sizeof(struct get_name_list_extended);
ea.data[0] = sp->u.iocb_cmd.u.mbx.in_mb[1]; /* amnt xfered */
}
for (i = 0; i < n; i++) {
e = &vha->gnl.l[i];
loop_id = le16_to_cpu(e->nport_handle);
/* mask out reserve bit */
loop_id = (loop_id & 0x7fff);
set_bit(loop_id, vha->hw->loop_id_map);
wwn = wwn_to_u64(e->port_name);
ql_dbg(ql_dbg_disc, vha, 0x20e8,
"%s %8phC %02x:%02x:%02x CLS %x/%x lid %x \n",
__func__, &wwn, e->port_id[2], e->port_id[1],
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
e->port_id[0], e->current_login_state, e->last_login_state,
(loop_id & 0x7fff));
}
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
INIT_LIST_HEAD(&h);
fcport = tf = NULL;
if (!list_empty(&vha->gnl.fcports))
list_splice_init(&vha->gnl.fcports, &h);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
scsi: qla2xxx: Fix gnl list corruption Current code does list element deletion and addition in and out of lock protection. This patch moves deletion behind lock. list_add double add: new=ffff9130b5eb89f8, prev=ffff9130b5eb89f8, next=ffff9130c6a715f0. ------------[ cut here ]------------ kernel BUG at lib/list_debug.c:31! invalid opcode: 0000 [#1] SMP PTI CPU: 1 PID: 182395 Comm: kworker/1:37 Kdump: loaded Tainted: G W OE --------- - - 4.18.0-193.el8.x86_64 #1 Hardware name: HP ProLiant DL160 Gen8, BIOS J03 02/10/2014 Workqueue: qla2xxx_wq qla2x00_iocb_work_fn [qla2xxx] RIP: 0010:__list_add_valid+0x41/0x50 Code: 85 94 00 00 00 48 39 c7 74 0b 48 39 d7 74 06 b8 01 00 00 00 c3 48 89 f2 4c 89 c1 48 89 fe 48 c7 c7 60 83 ad 97 e8 4d bd ce ff <0f> 0b 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 8b 07 48 8b 57 08 RSP: 0018:ffffaba306f47d68 EFLAGS: 00010046 RAX: 0000000000000058 RBX: ffff9130b5eb8800 RCX: 0000000000000006 RDX: 0000000000000000 RSI: 0000000000000096 RDI: ffff9130b7456a00 RBP: ffff9130c6a70a58 R08: 000000000008d7be R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000001 R12: ffff9130c6a715f0 R13: ffff9130b5eb8824 R14: ffff9130b5eb89f8 R15: ffff9130b5eb89f8 FS: 0000000000000000(0000) GS:ffff9130b7440000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007efcaaef11a0 CR3: 000000005200a002 CR4: 00000000000606e0 Call Trace: qla24xx_async_gnl+0x113/0x3c0 [qla2xxx] ? qla2x00_iocb_work_fn+0x53/0x80 [qla2xxx] ? process_one_work+0x1a7/0x3b0 ? worker_thread+0x30/0x390 ? create_worker+0x1a0/0x1a0 ? kthread+0x112/0x130 Link: https://lore.kernel.org/r/20211026115412.27691-3-njavali@marvell.com Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-10-26 11:54:01 +00:00
list_del_init(&fcport->gnl_entry);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
ea.fcport = fcport;
qla24xx_handle_gnl_done_event(vha, &ea);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
/* create new fcport if fw has knowledge of new sessions */
for (i = 0; i < n; i++) {
port_id_t id;
u64 wwnn;
e = &vha->gnl.l[i];
wwn = wwn_to_u64(e->port_name);
found = false;
list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
if (!memcmp((u8 *)&wwn, fcport->port_name,
WWN_SIZE)) {
found = true;
break;
}
}
id.b.domain = e->port_id[2];
id.b.area = e->port_id[1];
id.b.al_pa = e->port_id[0];
id.b.rsvd_1 = 0;
if (!found && wwn && !IS_SW_RESV_ADDR(id)) {
ql_dbg(ql_dbg_disc, vha, 0x2065,
"%s %d %8phC %06x post new sess\n",
__func__, __LINE__, (u8 *)&wwn, id.b24);
wwnn = wwn_to_u64(e->node_name);
qla24xx_post_newsess_work(vha, &id, (u8 *)&wwn,
(u8 *)&wwnn, NULL, 0);
}
}
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
vha->gnl.sent = 0;
if (!list_empty(&vha->gnl.fcports)) {
/* retrigger gnl */
list_for_each_entry_safe(fcport, tf, &vha->gnl.fcports,
gnl_entry) {
list_del_init(&fcport->gnl_entry);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
if (qla24xx_post_gnl_work(vha, fcport) == QLA_SUCCESS)
break;
}
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
{
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
unsigned long flags;
u16 *mb;
if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
return rval;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
ql_dbg(ql_dbg_disc, vha, 0x20d9,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"Async-gnlist WWPN %8phC \n", fcport->port_name);
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
fcport->flags |= FCF_ASYNC_SENT;
qla2x00_set_fcport_disc_state(fcport, DSC_GNL);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->last_rscn_gen = fcport->rscn_gen;
fcport->last_login_gen = fcport->login_gen;
list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports);
if (vha->gnl.sent) {
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return QLA_SUCCESS;
}
vha->gnl.sent = 1;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
sp->type = SRB_MB_IOCB;
sp->name = "gnlist";
sp->gen1 = fcport->rscn_gen;
sp->gen2 = fcport->login_gen;
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla24xx_async_gnl_sp_done);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
mb = sp->u.iocb_cmd.u.mbx.out_mb;
mb[0] = MBC_PORT_NODE_NAME_LIST;
mb[1] = BIT_2 | BIT_3;
mb[2] = MSW(vha->gnl.ldma);
mb[3] = LSW(vha->gnl.ldma);
mb[6] = MSW(MSD(vha->gnl.ldma));
mb[7] = LSW(MSD(vha->gnl.ldma));
mb[8] = vha->gnl.size;
mb[9] = vha->vp_idx;
ql_dbg(ql_dbg_disc, vha, 0x20da,
"Async-%s - OUT WWPN %8phC hndl %x\n",
sp->name, fcport->port_name, sp->handle);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
fcport->flags &= ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return rval;
}
int qla24xx_post_gnl_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_GNL);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
fcport->flags |= FCF_ASYNC_ACTIVE;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return qla2x00_post_work(vha, e);
}
static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
{
struct scsi_qla_host *vha = sp->vha;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport = sp->fcport;
u16 *mb = sp->u.iocb_cmd.u.mbx.in_mb;
struct event_arg ea;
ql_dbg(ql_dbg_disc, vha, 0x20db,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n",
sp->name, res, fcport->port_name, mb[1], mb[2]);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
if (res == QLA_FUNCTION_TIMEOUT)
goto done;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
memset(&ea, 0, sizeof(ea));
ea.fcport = fcport;
ea.sp = sp;
qla24xx_handle_gpdb_event(vha, &ea);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
done:
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in,
sp->u.iocb_cmd.u.mbx.in_dma);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
kref_put(&sp->cmd_kref, qla2x00_sp_release);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
if (vha->host->active_mode == MODE_TARGET)
return QLA_FUNCTION_FAILED;
e = qla2x00_alloc_work(vha, QLA_EVT_PRLI);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
return qla2x00_post_work(vha, e);
}
static void qla2x00_async_prli_sp_done(srb_t *sp, int res)
{
struct scsi_qla_host *vha = sp->vha;
struct srb_iocb *lio = &sp->u.iocb_cmd;
struct event_arg ea;
ql_dbg(ql_dbg_disc, vha, 0x2129,
"%s %8phC res %x\n", __func__,
sp->fcport->port_name, res);
sp->fcport->flags &= ~FCF_ASYNC_SENT;
if (!test_bit(UNLOADING, &vha->dpc_flags)) {
memset(&ea, 0, sizeof(ea));
ea.fcport = sp->fcport;
ea.data[0] = lio->u.logio.data[0];
ea.data[1] = lio->u.logio.data[1];
ea.iop[0] = lio->u.logio.iop[0];
ea.iop[1] = lio->u.logio.iop[1];
ea.sp = sp;
if (res == QLA_OS_TIMER_EXPIRED)
ea.data[0] = QLA_OS_TIMER_EXPIRED;
scsi: qla2xxx: Fix warning message due to adisc being flushed Fix warning message due to adisc being flushed. Linux kernel triggered a warning message where a different error code type is not matching up with the expected type. Add additional translation of one error code type to another. WARNING: CPU: 2 PID: 1131623 at drivers/scsi/qla2xxx/qla_init.c:498 qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] CPU: 2 PID: 1131623 Comm: drmgr Not tainted 5.13.0-rc1-autotest #1 .. GPR28: c000000aaa9c8890 c0080000079ab678 c00000140a104800 c00000002bd19000 NIP [c00800000790857c] qla2x00_async_adisc_sp_done+0x294/0x2b0 [qla2xxx] LR [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] Call Trace: [c00000001cdc3620] [c008000007908578] qla2x00_async_adisc_sp_done+0x290/0x2b0 [qla2xxx] (unreliable) [c00000001cdc3710] [c0080000078f3080] __qla2x00_abort_all_cmds+0x1b8/0x580 [qla2xxx] [c00000001cdc3840] [c0080000078f589c] qla2x00_abort_all_cmds+0x34/0xd0 [qla2xxx] [c00000001cdc3880] [c0080000079153d8] qla2x00_abort_isp_cleanup+0x3f0/0x570 [qla2xxx] [c00000001cdc3920] [c0080000078fb7e8] qla2x00_remove_one+0x3d0/0x480 [qla2xxx] [c00000001cdc39b0] [c00000000071c274] pci_device_remove+0x64/0x120 [c00000001cdc39f0] [c0000000007fb818] device_release_driver_internal+0x168/0x2a0 [c00000001cdc3a30] [c00000000070e304] pci_stop_bus_device+0xb4/0x100 [c00000001cdc3a70] [c00000000070e4f0] pci_stop_and_remove_bus_device+0x20/0x40 [c00000001cdc3aa0] [c000000000073940] pci_hp_remove_devices+0x90/0x130 [c00000001cdc3b30] [c0080000070704d0] disable_slot+0x38/0x90 [rpaphp] [ c00000001cdc3b60] [c00000000073eb4c] power_write_file+0xcc/0x180 [c00000001cdc3be0] [c0000000007354bc] pci_slot_attr_store+0x3c/0x60 [c00000001cdc3c00] [c00000000055f820] sysfs_kf_write+0x60/0x80 [c00000001cdc3c20] [c00000000055df10] kernfs_fop_write_iter+0x1a0/0x290 [c00000001cdc3c70] [c000000000447c4c] new_sync_write+0x14c/0x1d0 [c00000001cdc3d10] [c00000000044b134] vfs_write+0x224/0x330 [c00000001cdc3d60] [c00000000044b3f4] ksys_write+0x74/0x130 [c00000001cdc3db0] [c00000000002df70] system_call_exception+0x150/0x2d0 [c00000001cdc3e10] [c00000000000d45c] system_call_common+0xec/0x278 Link: https://lore.kernel.org/r/20220110050218.3958-5-njavali@marvell.com Cc: stable@vger.kernel.org Reported-by: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:05 +00:00
else if (res)
ea.data[0] = MBS_COMMAND_ERROR;
qla24xx_handle_prli_done_event(vha, &ea);
}
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
int
qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport)
{
srb_t *sp;
struct srb_iocb *lio;
int rval = QLA_FUNCTION_FAILED;
if (!vha->flags.online) {
ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC exit\n",
__func__, __LINE__, fcport->port_name);
return rval;
}
if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND ||
fcport->fw_login_state == DSC_LS_PRLI_PEND) &&
qla_dual_mode_enabled(vha)) {
ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC exit\n",
__func__, __LINE__, fcport->port_name);
return rval;
}
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
return rval;
fcport->flags |= FCF_ASYNC_SENT;
fcport->logout_completed = 0;
sp->type = SRB_PRLI_CMD;
sp->name = "prli";
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla2x00_async_prli_sp_done);
lio = &sp->u.iocb_cmd;
lio->u.logio.flags = 0;
if (NVME_TARGET(vha->hw, fcport))
lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI;
ql_dbg(ql_dbg_disc, vha, 0x211b,
"Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d fc4type %x priority %x %s.\n",
fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24,
fcport->login_retry, fcport->fc4_type, vha->hw->fc4_type_priority,
NVME_TARGET(vha->hw, fcport) ? "nvme" : "fcp");
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
fcport->flags |= FCF_LOGIN_NEEDED;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
goto done_free_sp;
}
return rval;
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
fcport->flags &= ~FCF_ASYNC_SENT;
return rval;
}
int qla24xx_post_gpdb_work(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
{
struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_GPDB);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
e->u.fcport.opt = opt;
fcport->flags |= FCF_ASYNC_ACTIVE;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return qla2x00_post_work(vha, e);
}
int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
{
srb_t *sp;
struct srb_iocb *mbx;
int rval = QLA_FUNCTION_FAILED;
u16 *mb;
dma_addr_t pd_dma;
struct port_database_24xx *pd;
struct qla_hw_data *ha = vha->hw;
if (IS_SESSION_DELETED(fcport)) {
ql_log(ql_log_warn, vha, 0xffff,
"%s: %8phC is being delete - not sending command.\n",
__func__, fcport->port_name);
fcport->flags &= ~FCF_ASYNC_ACTIVE;
return rval;
}
if (!vha->flags.online || fcport->flags & FCF_ASYNC_SENT) {
ql_log(ql_log_warn, vha, 0xffff,
"%s: %8phC online %d flags %x - not sending command.\n",
__func__, fcport->port_name, vha->flags.online, fcport->flags);
goto done;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
qla2x00_set_fcport_disc_state(fcport, DSC_GPDB);
fcport->flags |= FCF_ASYNC_SENT;
sp->type = SRB_MB_IOCB;
sp->name = "gpdb";
sp->gen1 = fcport->rscn_gen;
sp->gen2 = fcport->login_gen;
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
qla24xx_async_gpdb_sp_done);
pd = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (pd == NULL) {
ql_log(ql_log_warn, vha, 0xd043,
"Failed to allocate port database structure.\n");
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
goto done_free_sp;
}
mb = sp->u.iocb_cmd.u.mbx.out_mb;
mb[0] = MBC_GET_PORT_DATABASE;
mb[1] = fcport->loop_id;
mb[2] = MSW(pd_dma);
mb[3] = LSW(pd_dma);
mb[6] = MSW(MSD(pd_dma));
mb[7] = LSW(MSD(pd_dma));
mb[9] = vha->vp_idx;
mb[10] = opt;
mbx = &sp->u.iocb_cmd;
mbx->u.mbx.in = (void *)pd;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
mbx->u.mbx.in_dma = pd_dma;
ql_dbg(ql_dbg_disc, vha, 0x20dc,
"Async-%s %8phC hndl %x opt %x\n",
sp->name, fcport->port_name, sp->handle, opt);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return rval;
done_free_sp:
if (pd)
dma_pool_free(ha->s_dma_pool, pd, pd_dma);
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
kref_put(&sp->cmd_kref, qla2x00_sp_release);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->flags &= ~FCF_ASYNC_SENT;
done:
fcport->flags &= ~FCF_ASYNC_ACTIVE;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla24xx_post_gpdb_work(vha, fcport, opt);
return rval;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
static
void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
{
unsigned long flags;
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
ea->fcport->login_gen++;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
ea->fcport->deleted = 0;
ea->fcport->logout_on_delete = 1;
if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) {
vha->fcport_count++;
ea->fcport->login_succ = 1;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla24xx_sched_upd_fcport(ea->fcport);
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
} else if (ea->fcport->login_succ) {
/*
* We have an existing session. A late RSCN delivery
* must have triggered the session to be re-validate.
* Session is still valid.
*/
ql_dbg(ql_dbg_disc, vha, 0x20d6,
"%s %d %8phC session revalidate success\n",
__func__, __LINE__, ea->fcport->port_name);
qla2x00_set_fcport_disc_state(ea->fcport, DSC_LOGIN_COMPLETE);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static int qla_chk_secure_login(scsi_qla_host_t *vha, fc_port_t *fcport,
struct port_database_24xx *pd)
{
int rc = 0;
if (pd->secure_login) {
ql_dbg(ql_dbg_disc, vha, 0x104d,
"Secure Login established on %8phC\n",
fcport->port_name);
fcport->flags |= FCF_FCSP_DEVICE;
} else {
ql_dbg(ql_dbg_disc, vha, 0x104d,
"non-Secure Login %8phC",
fcport->port_name);
fcport->flags &= ~FCF_FCSP_DEVICE;
}
if (vha->hw->flags.edif_enabled) {
if (fcport->flags & FCF_FCSP_DEVICE) {
qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_AUTH_PEND);
/* Start edif prli timer & ring doorbell for app */
fcport->edif.rx_sa_set = 0;
fcport->edif.tx_sa_set = 0;
fcport->edif.rx_sa_pending = 0;
fcport->edif.tx_sa_pending = 0;
qla2x00_post_aen_work(vha, FCH_EVT_PORT_ONLINE,
fcport->d_id.b24);
if (DBELL_ACTIVE(vha)) {
ql_dbg(ql_dbg_disc, vha, 0x20ef,
"%s %d %8phC EDIF: post DB_AUTH: AUTH needed\n",
__func__, __LINE__, fcport->port_name);
fcport->edif.app_sess_online = 1;
qla_edb_eventcreate(vha, VND_CMD_AUTH_STATE_NEEDED,
fcport->d_id.b24, 0, fcport);
}
rc = 1;
} else if (qla_ini_mode_enabled(vha) || qla_dual_mode_enabled(vha)) {
ql_dbg(ql_dbg_disc, vha, 0x2117,
"%s %d %8phC post prli\n",
__func__, __LINE__, fcport->port_name);
qla24xx_post_prli_work(vha, fcport);
rc = 1;
}
}
return rc;
}
static
void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
{
fc_port_t *fcport = ea->fcport;
struct port_database_24xx *pd;
struct srb *sp = ea->sp;
uint8_t ls;
pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in;
fcport->flags &= ~FCF_ASYNC_SENT;
ql_dbg(ql_dbg_disc, vha, 0x20d2,
"%s %8phC DS %d LS %x fc4_type %x rc %x\n", __func__,
fcport->port_name, fcport->disc_state, pd->current_login_state,
fcport->fc4_type, ea->rc);
if (fcport->disc_state == DSC_DELETE_PEND) {
ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC\n",
__func__, __LINE__, fcport->port_name);
return;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (NVME_TARGET(vha->hw, fcport))
ls = pd->current_login_state >> 4;
else
ls = pd->current_login_state & 0xf;
if (ea->sp->gen2 != fcport->login_gen) {
/* target side must have changed it. */
ql_dbg(ql_dbg_disc, vha, 0x20d3,
"%s %8phC generation changed\n",
__func__, fcport->port_name);
return;
} else if (ea->sp->gen1 != fcport->rscn_gen) {
qla_rscn_replay(fcport);
qlt_schedule_sess_for_deletion(fcport);
ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC, ls %x\n",
__func__, __LINE__, fcport->port_name, ls);
return;
}
switch (ls) {
case PDS_PRLI_COMPLETE:
__qla24xx_parse_gpdb(vha, fcport, pd);
break;
case PDS_PLOGI_COMPLETE:
if (qla_chk_secure_login(vha, fcport, pd)) {
ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC, ls %x\n",
__func__, __LINE__, fcport->port_name, ls);
return;
}
fallthrough;
case PDS_PLOGI_PENDING:
case PDS_PRLI_PENDING:
case PDS_PRLI2_PENDING:
/* Set discovery state back to GNL to Relogin attempt */
if (qla_dual_mode_enabled(vha) ||
qla_ini_mode_enabled(vha)) {
qla2x00_set_fcport_disc_state(fcport, DSC_GNL);
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
}
ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC, ls %x\n",
__func__, __LINE__, fcport->port_name, ls);
return;
case PDS_LOGO_PENDING:
case PDS_PORT_UNAVAILABLE:
default:
ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n",
__func__, __LINE__, fcport->port_name);
qlt_schedule_sess_for_deletion(fcport);
return;
}
__qla24xx_handle_gpdb_event(vha, ea);
} /* gpdb event */
static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u8 login = 0;
int rc;
ql_dbg(ql_dbg_disc, vha, 0x307b,
"%s %8phC DS %d LS %d lid %d retries=%d\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, fcport->loop_id, fcport->login_retry);
if (qla_tgt_mode_enabled(vha))
return;
if (qla_dual_mode_enabled(vha)) {
if (N2N_TOPO(vha->hw)) {
u64 mywwn, wwn;
mywwn = wwn_to_u64(vha->port_name);
wwn = wwn_to_u64(fcport->port_name);
if (mywwn > wwn)
login = 1;
else if ((fcport->fw_login_state == DSC_LS_PLOGI_COMP)
&& time_after_eq(jiffies,
fcport->plogi_nack_done_deadline))
login = 1;
} else {
login = 1;
}
} else {
/* initiator mode */
login = 1;
}
if (login && fcport->login_retry) {
fcport->login_retry--;
if (fcport->loop_id == FC_NO_LOOP_ID) {
fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
rc = qla2x00_find_new_loop_id(vha, fcport);
if (rc) {
ql_dbg(ql_dbg_disc, vha, 0x20e6,
"%s %d %8phC post del sess - out of loopid\n",
__func__, __LINE__, fcport->port_name);
fcport->scan_state = 0;
qlt_schedule_sess_for_deletion(fcport);
return;
}
}
ql_dbg(ql_dbg_disc, vha, 0x20bf,
"%s %d %8phC post login\n",
__func__, __LINE__, fcport->port_name);
qla2x00_post_async_login_work(vha, fcport, NULL);
}
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u16 data[2];
u16 sec;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
ql_dbg(ql_dbg_disc, vha, 0x20d8,
"%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d lid %d scan %d fc4type %x\n",
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, fcport->login_pause, fcport->flags,
fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen,
fcport->login_gen, fcport->loop_id, fcport->scan_state,
fcport->fc4_type);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (fcport->scan_state != QLA_FCPORT_FOUND ||
fcport->disc_state == DSC_DELETE_PEND)
return 0;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if ((fcport->loop_id != FC_NO_LOOP_ID) &&
qla_dual_mode_enabled(vha) &&
((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
(fcport->fw_login_state == DSC_LS_PRLI_PEND)))
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return 0;
if (fcport->fw_login_state == DSC_LS_PLOGI_COMP &&
!N2N_TOPO(vha->hw)) {
if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) {
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return 0;
}
}
/* Target won't initiate port login if fabric is present */
if (vha->host->active_mode == MODE_TARGET && !N2N_TOPO(vha->hw))
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return 0;
if (fcport->flags & (FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE)) {
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return 0;
}
switch (fcport->disc_state) {
case DSC_DELETED:
switch (vha->hw->current_topology) {
case ISP_CFG_N:
if (fcport_is_smaller(fcport)) {
/* this adapter is bigger */
if (fcport->login_retry) {
if (fcport->loop_id == FC_NO_LOOP_ID) {
qla2x00_find_new_loop_id(vha,
fcport);
fcport->fw_login_state =
DSC_LS_PORT_UNAVAIL;
}
fcport->login_retry--;
qla_post_els_plogi_work(vha, fcport);
} else {
ql_log(ql_log_info, vha, 0x705d,
"Unable to reach remote port %8phC",
fcport->port_name);
}
} else {
qla24xx_post_gnl_work(vha, fcport);
}
break;
default:
if (fcport->loop_id == FC_NO_LOOP_ID) {
ql_dbg(ql_dbg_disc, vha, 0x20bd,
"%s %d %8phC post gnl\n",
__func__, __LINE__, fcport->port_name);
qla24xx_post_gnl_work(vha, fcport);
} else {
qla_chk_n2n_b4_login(vha, fcport);
}
break;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
break;
case DSC_GNL:
switch (vha->hw->current_topology) {
case ISP_CFG_N:
if ((fcport->current_login_state & 0xf) == 0x6) {
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post GPDB work\n",
__func__, __LINE__, fcport->port_name);
fcport->chip_reset =
vha->hw->base_qpair->chip_reset;
qla24xx_post_gpdb_work(vha, fcport, 0);
} else {
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post %s PRLI\n",
__func__, __LINE__, fcport->port_name,
NVME_TARGET(vha->hw, fcport) ? "NVME" :
"FC");
qla24xx_post_prli_work(vha, fcport);
}
break;
default:
if (fcport->login_pause) {
ql_dbg(ql_dbg_disc, vha, 0x20d8,
"%s %d %8phC exit\n",
__func__, __LINE__,
fcport->port_name);
fcport->last_rscn_gen = fcport->rscn_gen;
fcport->last_login_gen = fcport->login_gen;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
break;
}
qla_chk_n2n_b4_login(vha, fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
}
break;
case DSC_LOGIN_FAILED:
if (N2N_TOPO(vha->hw))
qla_chk_n2n_b4_login(vha, fcport);
else
qlt_schedule_sess_for_deletion(fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
case DSC_LOGIN_COMPLETE:
/* recheck login state */
data[0] = data[1] = 0;
qla2x00_post_async_adisc_work(vha, fcport, data);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
case DSC_LOGIN_PEND:
if (vha->hw->flags.edif_enabled)
break;
if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post %s PRLI\n",
__func__, __LINE__, fcport->port_name,
NVME_TARGET(vha->hw, fcport) ? "NVME" : "FC");
qla24xx_post_prli_work(vha, fcport);
}
break;
case DSC_UPD_FCPORT:
sec = jiffies_to_msecs(jiffies -
fcport->jiffies_at_registration)/1000;
if (fcport->sec_since_registration < sec && sec &&
!(sec % 60)) {
fcport->sec_since_registration = sec;
ql_dbg(ql_dbg_disc, fcport->vha, 0xffff,
"%s %8phC - Slow Rport registration(%d Sec)\n",
__func__, fcport->port_name, sec);
}
if (fcport->next_disc_state != DSC_DELETE_PEND)
fcport->next_disc_state = DSC_ADISC;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
break;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
default:
break;
}
return 0;
}
int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
u8 *port_name, u8 *node_name, void *pla, u8 fc4_type)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
{
struct qla_work_evt *e;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
e = qla2x00_alloc_work(vha, QLA_EVT_NEW_SESS);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.new_sess.id = *id;
e->u.new_sess.pla = pla;
e->u.new_sess.fc4_type = fc4_type;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
memcpy(e->u.new_sess.port_name, port_name, WWN_SIZE);
if (node_name)
memcpy(e->u.new_sess.node_name, node_name, WWN_SIZE);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return qla2x00_post_work(vha, e);
}
void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
{
fc_port_t *fcport;
unsigned long flags;
switch (ea->id.b.rsvd_1) {
case RSCN_PORT_ADDR:
fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
if (fcport) {
if (ql2xfc2target &&
fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE) {
ql_dbg(ql_dbg_disc, vha, 0x2115,
"Delaying session delete for FCP2 portid=%06x %8phC ",
fcport->d_id.b24, fcport->port_name);
return;
}
if (vha->hw->flags.edif_enabled && DBELL_ACTIVE(vha)) {
/*
* On ipsec start by remote port, Target port
* may use RSCN to trigger initiator to
* relogin. If driver is already in the
* process of a relogin, then ignore the RSCN
* and allow the current relogin to continue.
* This reduces thrashing of the connection.
*/
if (atomic_read(&fcport->state) == FCS_ONLINE) {
/*
* If state = online, then set scan_needed=1 to do relogin.
* Otherwise we're already in the middle of a relogin
*/
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
} else {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
break;
case RSCN_AREA_ADDR:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
continue;
if ((ea->id.b24 & 0xffff00) == (fcport->d_id.b24 & 0xffff00)) {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
break;
case RSCN_DOM_ADDR:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
continue;
if ((ea->id.b24 & 0xff0000) == (fcport->d_id.b24 & 0xff0000)) {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
break;
case RSCN_FAB_ADDR:
default:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
continue;
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
break;
}
spin_lock_irqsave(&vha->work_lock, flags);
if (vha->scan.scan_flags == 0) {
ql_dbg(ql_dbg_disc, vha, 0xffff, "%s: schedule\n", __func__);
vha->scan.scan_flags |= SF_QUEUED;
schedule_delayed_work(&vha->scan.scan_work, 5);
}
spin_unlock_irqrestore(&vha->work_lock, flags);
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
struct event_arg *ea)
{
fc_port_t *fcport = ea->fcport;
if (test_bit(UNLOADING, &vha->dpc_flags))
return;
ql_dbg(ql_dbg_disc, vha, 0x2102,
"%s %8phC DS %d LS %d P %d del %d cnfl %p rscn %d|%d login %d|%d fl %x\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, fcport->login_pause,
fcport->deleted, fcport->conflict,
fcport->last_rscn_gen, fcport->rscn_gen,
fcport->last_login_gen, fcport->login_gen,
fcport->flags);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (fcport->last_rscn_gen != fcport->rscn_gen) {
ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gnl\n",
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
__func__, __LINE__, fcport->port_name);
qla24xx_post_gnl_work(vha, fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
return;
}
qla24xx_fcport_handle_login(vha, fcport);
}
void qla_handle_els_plogi_done(scsi_qla_host_t *vha,
struct event_arg *ea)
{
if (N2N_TOPO(vha->hw) && fcport_is_smaller(ea->fcport) &&
vha->hw->flags.edif_enabled) {
/* check to see if App support Secure */
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
return;
}
/* for pure Target Mode, PRLI will not be initiated */
if (vha->host->active_mode == MODE_TARGET)
return;
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post PRLI\n",
__func__, __LINE__, ea->fcport->port_name);
qla24xx_post_prli_work(vha, ea->fcport);
}
/*
* RSCN(s) came in for this fcport, but the RSCN(s) was not able
* to be consumed by the fcport
*/
void qla_rscn_replay(fc_port_t *fcport)
{
struct event_arg ea;
switch (fcport->disc_state) {
case DSC_DELETE_PEND:
return;
default:
break;
}
if (fcport->scan_needed) {
memset(&ea, 0, sizeof(ea));
ea.id = fcport->d_id;
ea.id.b.rsvd_1 = RSCN_PORT_ADDR;
qla2x00_handle_rscn(fcport->vha, &ea);
}
}
static void
qla2x00_tmf_iocb_timeout(void *data)
{
srb_t *sp = data;
struct srb_iocb *tmf = &sp->u.iocb_cmd;
int rc, h;
unsigned long flags;
if (sp->type == SRB_MARKER) {
complete(&tmf->u.tmf.comp);
return;
}
rc = qla24xx_async_abort_cmd(sp, false);
if (rc) {
spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
if (sp->qpair->req->outstanding_cmds[h] == sp) {
sp->qpair->req->outstanding_cmds[h] = NULL;
qla_put_fw_resources(sp->qpair, &sp->iores);
break;
}
}
spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
tmf->u.tmf.comp_status = cpu_to_le16(CS_TIMEOUT);
tmf->u.tmf.data = QLA_FUNCTION_FAILED;
complete(&tmf->u.tmf.comp);
}
}
static void qla_marker_sp_done(srb_t *sp, int res)
{
struct srb_iocb *tmf = &sp->u.iocb_cmd;
if (res != QLA_SUCCESS)
ql_dbg(ql_dbg_taskm, sp->vha, 0x8004,
"Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n",
sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
sp->u.iocb_cmd.u.tmf.data = res;
complete(&tmf->u.tmf.comp);
}
#define START_SP_W_RETRIES(_sp, _rval) \
{\
int cnt = 5; \
do { \
_rval = qla2x00_start_sp(_sp); \
if (_rval == EAGAIN) \
msleep(1); \
else \
break; \
cnt--; \
} while (cnt); \
}
/**
* qla26xx_marker: send marker IOCB and wait for the completion of it.
* @arg: pointer to argument list.
* It is assume caller will provide an fcport pointer and modifier
*/
static int
qla26xx_marker(struct tmf_arg *arg)
{
struct scsi_qla_host *vha = arg->vha;
struct srb_iocb *tm_iocb;
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
fc_port_t *fcport = arg->fcport;
if (TMF_NOT_READY(arg->fcport)) {
ql_dbg(ql_dbg_taskm, vha, 0x8039,
"FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
fcport->loop_id, fcport->d_id.b24,
arg->modifier, arg->lun, arg->qpair->id);
return QLA_SUSPENDED;
}
/* ref: INIT */
sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
if (!sp)
goto done;
sp->type = SRB_MARKER;
sp->name = "marker";
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done);
sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
tm_iocb = &sp->u.iocb_cmd;
init_completion(&tm_iocb->u.tmf.comp);
tm_iocb->u.tmf.modifier = arg->modifier;
tm_iocb->u.tmf.lun = arg->lun;
tm_iocb->u.tmf.loop_id = fcport->loop_id;
tm_iocb->u.tmf.vp_index = vha->vp_idx;
START_SP_W_RETRIES(sp, rval);
ql_dbg(ql_dbg_taskm, vha, 0x8006,
"Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
sp->handle, fcport->loop_id, fcport->d_id.b24,
arg->modifier, arg->lun, sp->qpair->id, rval);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x8031,
"Marker IOCB send failure (%x).\n", rval);
goto done_free_sp;
}
wait_for_completion(&tm_iocb->u.tmf.comp);
rval = tm_iocb->u.tmf.data;
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x8019,
"Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
sp->handle, fcport->loop_id, fcport->d_id.b24,
arg->modifier, arg->lun, sp->qpair->id, rval);
}
done_free_sp:
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
return rval;
}
static void qla2x00_tmf_sp_done(srb_t *sp, int res)
{
struct srb_iocb *tmf = &sp->u.iocb_cmd;
if (res)
tmf->u.tmf.data = res;
complete(&tmf->u.tmf.comp);
}
static int
__qla2x00_async_tm_cmd(struct tmf_arg *arg)
{
struct scsi_qla_host *vha = arg->vha;
struct srb_iocb *tm_iocb;
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
fc_port_t *fcport = arg->fcport;
if (TMF_NOT_READY(arg->fcport)) {
ql_dbg(ql_dbg_taskm, vha, 0x8032,
"FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
fcport->loop_id, fcport->d_id.b24,
arg->modifier, arg->lun, arg->qpair->id);
return QLA_SUSPENDED;
}
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
if (!sp)
goto done;
qla_vha_mark_busy(vha);
sp->type = SRB_TM_CMD;
sp->name = "tmf";
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha),
qla2x00_tmf_sp_done);
sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
tm_iocb = &sp->u.iocb_cmd;
init_completion(&tm_iocb->u.tmf.comp);
tm_iocb->u.tmf.flags = arg->flags;
tm_iocb->u.tmf.lun = arg->lun;
START_SP_W_RETRIES(sp, rval);
ql_dbg(ql_dbg_taskm, vha, 0x802f,
"Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
sp->handle, fcport->loop_id, fcport->d_id.b24,
arg->flags, arg->lun, sp->qpair->id, rval);
if (rval != QLA_SUCCESS)
goto done_free_sp;
wait_for_completion(&tm_iocb->u.tmf.comp);
rval = tm_iocb->u.tmf.data;
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x8030,
"TM IOCB failed (%x).\n", rval);
}
if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
rval = qla26xx_marker(arg);
done_free_sp:
scsi: qla2xxx: Implement ref count for SRB The timeout handler and the done function are racing. When qla2x00_async_iocb_timeout() starts to run it can be preempted by the normal response path (via the firmware?). qla24xx_async_gpsc_sp_done() releases the SRB unconditionally. When scheduling back to qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed sp->qpair pointer: qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21. qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21 qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400. qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5 BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx] Obvious solution to this is to introduce a reference counter. One reference is taken for the normal code path (the 'good' case) and one for the timeout path. As we always race between the normal good case and the timeout/abort handler we need to serialize it. Also we cannot assume any order between the handlers. Since this is slow path we can use proper synchronization via locks. When we are able to cancel a timer (del_timer returns 1) we know there can't be any error handling in progress because the timeout handler hasn't expired yet, thus we can safely decrement the refcounter by one. If we are not able to cancel the timer, we know an abort handler is running. We have to make sure we call sp->done() in the abort handlers before calling kref_put(). Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:03 +00:00
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
done:
return rval;
}
static void qla_put_tmf(fc_port_t *fcport)
{
struct scsi_qla_host *vha = fcport->vha;
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
fcport->active_tmf--;
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static
int qla_get_tmf(fc_port_t *fcport)
{
struct scsi_qla_host *vha = fcport->vha;
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
int rc = 0;
LIST_HEAD(tmf_elem);
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_add_tail(&tmf_elem, &fcport->tmf_pending);
while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
msleep(1);
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (TMF_NOT_READY(fcport)) {
ql_log(ql_log_warn, vha, 0x802c,
"Unable to acquire TM resource due to disruption.\n");
rc = EIO;
break;
}
if (fcport->active_tmf < MAX_ACTIVE_TMF &&
list_is_first(&tmf_elem, &fcport->tmf_pending))
break;
}
list_del(&tmf_elem);
if (!rc)
fcport->active_tmf++;
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return rc;
}
int
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
uint32_t tag)
{
struct scsi_qla_host *vha = fcport->vha;
struct qla_qpair *qpair;
struct tmf_arg a;
int i, rval = QLA_SUCCESS;
if (TMF_NOT_READY(fcport))
return QLA_SUSPENDED;
a.vha = fcport->vha;
a.fcport = fcport;
a.lun = lun;
if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
a.modifier = MK_SYNC_ID_LUN;
if (qla_get_tmf(fcport))
return QLA_FUNCTION_FAILED;
} else {
a.modifier = MK_SYNC_ID;
}
if (vha->hw->mqenable) {
for (i = 0; i < vha->hw->num_qpairs; i++) {
qpair = vha->hw->queue_pair_map[i];
if (!qpair)
continue;
if (TMF_NOT_READY(fcport)) {
ql_log(ql_log_warn, vha, 0x8026,
"Unable to send TM due to disruption.\n");
rval = QLA_SUSPENDED;
break;
}
a.qpair = qpair;
a.flags = flags|TCF_NOTMCMD_TO_TARGET;
rval = __qla2x00_async_tm_cmd(&a);
if (rval)
break;
}
}
if (rval)
goto bailout;
a.qpair = vha->hw->base_qpair;
a.flags = flags;
rval = __qla2x00_async_tm_cmd(&a);
bailout:
if (a.modifier == MK_SYNC_ID_LUN)
qla_put_tmf(fcport);
return rval;
}
int
qla24xx_async_abort_command(srb_t *sp)
{
unsigned long flags = 0;
uint32_t handle;
fc_port_t *fcport = sp->fcport;
struct qla_qpair *qpair = sp->qpair;
struct scsi_qla_host *vha = fcport->vha;
struct req_que *req = qpair->req;
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
if (req->outstanding_cmds[handle] == sp)
break;
}
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
if (handle == req->num_outstanding_cmds) {
/* Command not found. */
return QLA_ERR_NOT_FOUND;
}
if (sp->type == SRB_FXIOCB_DCMD)
return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
FXDISC_ABORT_IOCTL);
return qla24xx_async_abort_cmd(sp, true);
}
static void
qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
{
struct srb *sp;
WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n",
ea->data[0]);
switch (ea->data[0]) {
case MBS_COMMAND_COMPLETE:
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post gpdb\n",
__func__, __LINE__, ea->fcport->port_name);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
ea->fcport->nvme_prli_service_param = ea->iop[0];
if (ea->iop[0] & NVME_PRLI_SP_FIRST_BURST)
ea->fcport->nvme_first_burst_size =
(ea->iop[1] & 0xffff) * 512;
else
ea->fcport->nvme_first_burst_size = 0;
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
break;
default:
sp = ea->sp;
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC priority %s, fc4type %x prev try %s\n",
__func__, __LINE__, ea->fcport->port_name,
vha->hw->fc4_type_priority == FC4_PRIORITY_FCP ?
"FCP" : "NVMe", ea->fcport->fc4_type,
(sp->u.iocb_cmd.u.logio.flags & SRB_LOGIN_NVME_PRLI) ?
"NVME" : "FCP");
if (NVME_FCP_TARGET(ea->fcport)) {
if (sp->u.iocb_cmd.u.logio.flags & SRB_LOGIN_NVME_PRLI)
ea->fcport->do_prli_nvme = 0;
else
ea->fcport->do_prli_nvme = 1;
} else {
ea->fcport->do_prli_nvme = 0;
}
if (N2N_TOPO(vha->hw)) {
if (ea->fcport->n2n_link_reset_cnt ==
vha->hw->login_retry_count &&
ea->fcport->flags & FCF_FCSP_DEVICE) {
/* remote authentication app just started */
ea->fcport->n2n_link_reset_cnt = 0;
}
if (ea->fcport->n2n_link_reset_cnt <
vha->hw->login_retry_count) {
ea->fcport->n2n_link_reset_cnt++;
vha->relogin_jif = jiffies + 2 * HZ;
/*
* PRLI failed. Reset link to kick start
* state machine
*/
set_bit(N2N_LINK_RESET, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
} else {
ql_log(ql_log_warn, vha, 0x2119,
"%s %d %8phC Unable to reconnect\n",
__func__, __LINE__,
ea->fcport->port_name);
}
} else {
/*
* switch connect. login failed. Take connection down
* and allow relogin to retrigger
*/
ea->fcport->flags &= ~FCF_ASYNC_SENT;
ea->fcport->keep_nport_handle = 0;
ea->fcport->logout_on_delete = 1;
qlt_schedule_sess_for_deletion(ea->fcport);
}
break;
}
}
void
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
{
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
port_id_t cid; /* conflict Nport id */
u16 lid;
struct fc_port *conflict_fcport;
unsigned long flags;
struct fc_port *fcport = ea->fcport;
ql_dbg(ql_dbg_disc, vha, 0xffff,
"%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d data %x|%x iop %x|%x\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen,
ea->sp->gen1, fcport->rscn_gen,
ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]);
if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
(fcport->fw_login_state == DSC_LS_PRLI_PEND)) {
ql_dbg(ql_dbg_disc, vha, 0x20ea,
"%s %d %8phC Remote is trying to login\n",
__func__, __LINE__, fcport->port_name);
return;
}
if ((fcport->disc_state == DSC_DELETE_PEND) ||
(fcport->disc_state == DSC_DELETED)) {
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return;
}
if (ea->sp->gen2 != fcport->login_gen) {
/* target side must have changed it. */
ql_dbg(ql_dbg_disc, vha, 0x20d3,
"%s %8phC generation changed\n",
__func__, fcport->port_name);
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return;
} else if (ea->sp->gen1 != fcport->rscn_gen) {
ql_dbg(ql_dbg_disc, vha, 0x20d3,
"%s %8phC RSCN generation changed\n",
__func__, fcport->port_name);
qla_rscn_replay(fcport);
qlt_schedule_sess_for_deletion(fcport);
return;
}
WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n",
ea->data[0]);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
switch (ea->data[0]) {
case MBS_COMMAND_COMPLETE:
/*
* Driver must validate login state - If PRLI not complete,
* force a relogin attempt via implicit LOGO, PLOGI, and PRLI
* requests.
*/
if (vha->hw->flags.edif_enabled) {
set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
ea->fcport->send_els_logo = 0;
ea->fcport->fw_login_state = DSC_LS_PLOGI_COMP;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
} else {
if (NVME_TARGET(vha->hw, fcport)) {
ql_dbg(ql_dbg_disc, vha, 0x2117,
"%s %d %8phC post prli\n",
__func__, __LINE__, fcport->port_name);
qla24xx_post_prli_work(vha, fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ea,
"%s %d %8phC LoopID 0x%x in use with %06x. post gpdb\n",
__func__, __LINE__, fcport->port_name,
fcport->loop_id, fcport->d_id.b24);
set_bit(fcport->loop_id, vha->hw->loop_id_map);
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
fcport->chip_reset = vha->hw->base_qpair->chip_reset;
fcport->logout_on_delete = 1;
fcport->send_els_logo = 0;
fcport->fw_login_state = DSC_LS_PRLI_COMP;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
qla24xx_post_gpdb_work(vha, fcport, 0);
}
}
break;
case MBS_COMMAND_ERROR:
ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n",
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
__func__, __LINE__, ea->fcport->port_name, ea->data[1]);
scsi: qla2xxx: Fix scheduling while atomic The driver makes a call into midlayer (fc_remote_port_delete) which can put the thread to sleep. The thread that originates the call is in interrupt context. The combination of the two trigger a crash. Schedule the call in non-interrupt context where it is more safe. kernel: BUG: scheduling while atomic: swapper/7/0/0x00010000 kernel: Call Trace: kernel: <IRQ> kernel: dump_stack+0x66/0x81 kernel: __schedule_bug.cold.90+0x5/0x1d kernel: __schedule+0x7af/0x960 kernel: schedule+0x28/0x80 kernel: schedule_timeout+0x26d/0x3b0 kernel: wait_for_completion+0xb4/0x140 kernel: ? wake_up_q+0x70/0x70 kernel: __wait_rcu_gp+0x12c/0x160 kernel: ? sdev_evt_alloc+0xc0/0x180 [scsi_mod] kernel: synchronize_sched+0x6c/0x80 kernel: ? call_rcu_bh+0x20/0x20 kernel: ? __bpf_trace_rcu_invoke_callback+0x10/0x10 kernel: sdev_evt_alloc+0xfd/0x180 [scsi_mod] kernel: starget_for_each_device+0x85/0xb0 [scsi_mod] kernel: ? scsi_init_io+0x360/0x3d0 [scsi_mod] kernel: scsi_init_io+0x388/0x3d0 [scsi_mod] kernel: device_for_each_child+0x54/0x90 kernel: fc_remote_port_delete+0x70/0xe0 [scsi_transport_fc] kernel: qla2x00_schedule_rport_del+0x62/0xf0 [qla2xxx] kernel: qla2x00_mark_device_lost+0x9c/0xd0 [qla2xxx] kernel: qla24xx_handle_plogi_done_event+0x55f/0x570 [qla2xxx] kernel: qla2x00_async_login_sp_done+0xd2/0x100 [qla2xxx] kernel: qla24xx_logio_entry+0x13a/0x3c0 [qla2xxx] kernel: qla24xx_process_response_queue+0x306/0x400 [qla2xxx] kernel: qla24xx_msix_rsp_q+0x3f/0xb0 [qla2xxx] kernel: __handle_irq_event_percpu+0x40/0x180 kernel: handle_irq_event_percpu+0x30/0x80 kernel: handle_irq_event+0x36/0x60 Link: https://lore.kernel.org/r/20220110050218.3958-7-njavali@marvell.com Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-01-10 05:02:07 +00:00
qlt_schedule_sess_for_deletion(ea->fcport);
break;
case MBS_LOOP_ID_USED:
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
/* data[1] = IO PARAM 1 = nport ID */
cid.b.domain = (ea->iop[1] >> 16) & 0xff;
cid.b.area = (ea->iop[1] >> 8) & 0xff;
cid.b.al_pa = ea->iop[1] & 0xff;
cid.b.rsvd_1 = 0;
ql_dbg(ql_dbg_disc, vha, 0x20ec,
"%s %d %8phC lid %#x in use with pid %06x post gnl\n",
__func__, __LINE__, ea->fcport->port_name,
ea->fcport->loop_id, cid.b24);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
ea->fcport->loop_id = FC_NO_LOOP_ID;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla24xx_post_gnl_work(vha, ea->fcport);
break;
case MBS_PORT_ID_USED:
lid = ea->iop[1] & 0xffff;
qlt_find_sess_invalidate_other(vha,
wwn_to_u64(ea->fcport->port_name),
ea->fcport->d_id, lid, &conflict_fcport);
if (conflict_fcport) {
/*
* Another fcport share the same loop_id/nport id.
* Conflict fcport needs to finish cleanup before this
* fcport can proceed to login.
*/
conflict_fcport->conflict = ea->fcport;
ea->fcport->login_pause = 1;
ql_dbg(ql_dbg_disc, vha, 0x20ed,
"%s %d %8phC NPortId %06x inuse with loopid 0x%x.\n",
__func__, __LINE__, ea->fcport->port_name,
ea->fcport->d_id.b24, lid);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ed,
"%s %d %8phC NPortId %06x inuse with loopid 0x%x. sched delete\n",
__func__, __LINE__, ea->fcport->port_name,
ea->fcport->d_id.b24, lid);
qla2x00_clear_loop_id(ea->fcport);
set_bit(lid, vha->hw->loop_id_map);
ea->fcport->loop_id = lid;
ea->fcport->keep_nport_handle = 0;
ea->fcport->logout_on_delete = 1;
qlt_schedule_sess_for_deletion(ea->fcport);
}
break;
}
return;
}
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
static int
qla83xx_nic_core_fw_load(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
struct qla_hw_data *ha = vha->hw;
uint32_t idc_major_ver, idc_minor_ver;
uint16_t config[4];
qla83xx_idc_lock(vha, 0);
/* SV: TODO: Assign initialization timeout from
* flash-info / other param
*/
ha->fcoe_dev_init_timeout = QLA83XX_IDC_INITIALIZATION_TIMEOUT;
ha->fcoe_reset_timeout = QLA83XX_IDC_RESET_ACK_TIMEOUT;
/* Set our fcoe function presence */
if (__qla83xx_set_drv_presence(vha) != QLA_SUCCESS) {
ql_dbg(ql_dbg_p3p, vha, 0xb077,
"Error while setting DRV-Presence.\n");
rval = QLA_FUNCTION_FAILED;
goto exit;
}
/* Decide the reset ownership */
qla83xx_reset_ownership(vha);
/*
* On first protocol driver load:
* Init-Owner: Set IDC-Major-Version and Clear IDC-Lock-Recovery
* register.
* Others: Check compatibility with current IDC Major version.
*/
qla83xx_rd_reg(vha, QLA83XX_IDC_MAJOR_VERSION, &idc_major_ver);
if (ha->flags.nic_core_reset_owner) {
/* Set IDC Major version */
idc_major_ver = QLA83XX_SUPP_IDC_MAJOR_VERSION;
qla83xx_wr_reg(vha, QLA83XX_IDC_MAJOR_VERSION, idc_major_ver);
/* Clearing IDC-Lock-Recovery register */
qla83xx_wr_reg(vha, QLA83XX_IDC_LOCK_RECOVERY, 0);
} else if (idc_major_ver != QLA83XX_SUPP_IDC_MAJOR_VERSION) {
/*
* Clear further IDC participation if we are not compatible with
* the current IDC Major Version.
*/
ql_log(ql_log_warn, vha, 0xb07d,
"Failing load, idc_major_ver=%d, expected_major_ver=%d.\n",
idc_major_ver, QLA83XX_SUPP_IDC_MAJOR_VERSION);
__qla83xx_clear_drv_presence(vha);
rval = QLA_FUNCTION_FAILED;
goto exit;
}
/* Each function sets its supported Minor version. */
qla83xx_rd_reg(vha, QLA83XX_IDC_MINOR_VERSION, &idc_minor_ver);
idc_minor_ver |= (QLA83XX_SUPP_IDC_MINOR_VERSION << (ha->portnum * 2));
qla83xx_wr_reg(vha, QLA83XX_IDC_MINOR_VERSION, idc_minor_ver);
if (ha->flags.nic_core_reset_owner) {
memset(config, 0, sizeof(config));
if (!qla81xx_get_port_config(vha, config))
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
QLA8XXX_DEV_READY);
}
rval = qla83xx_idc_state_handler(vha);
exit:
qla83xx_idc_unlock(vha, 0);
return rval;
}
/*
* qla2x00_initialize_adapter
* Initialize board.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success
*/
int
qla2x00_initialize_adapter(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
/* Clear adapter flags. */
vha->flags.online = 0;
ha->flags.chip_reset_done = 0;
vha->flags.reset_active = 0;
ha->flags.pci_channel_io_perm_failure = 0;
ha->flags.eeh_busy = 0;
vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
atomic_set(&vha->loop_state, LOOP_DOWN);
vha->device_flags = DFLG_NO_CABLE;
vha->dpc_flags = 0;
vha->flags.management_server_logged_in = 0;
vha->marker_needed = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
set_bit(0, ha->req_qid_map);
set_bit(0, ha->rsp_qid_map);
ql_dbg(ql_dbg_init, vha, 0x0040,
"Configuring PCI space...\n");
rval = ha->isp_ops->pci_config(vha);
if (rval) {
ql_log(ql_log_warn, vha, 0x0044,
"Unable to configure PCI space.\n");
return (rval);
}
ha->isp_ops->reset_chip(vha);
/* Check for secure flash support */
if (IS_QLA28XX(ha)) {
if (rd_reg_word(&reg->mailbox12) & BIT_0)
ha->flags.secure_adapter = 1;
ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n",
(ha->flags.secure_adapter) ? "Yes" : "No");
}
rval = qla2xxx_get_flash_info(vha);
if (rval) {
ql_log(ql_log_fatal, vha, 0x004f,
"Unable to validate FLASH data.\n");
return rval;
}
if (IS_QLA8044(ha)) {
qla8044_read_reset_template(vha);
/* NOTE: If ql2xdontresethba==1, set IDC_CTRL DONTRESET_BIT0.
* If DONRESET_BIT0 is set, drivers should not set dev_state
* to NEED_RESET. But if NEED_RESET is set, drivers should
* should honor the reset. */
if (ql2xdontresethba == 1)
qla8044_set_idc_dontreset(vha);
}
ha->isp_ops->get_flash_version(vha, req->ring);
ql_dbg(ql_dbg_init, vha, 0x0061,
"Configure NVRAM parameters...\n");
/* Let priority default to FCP, can be overridden by nvram_config */
ha->fc4_type_priority = FC4_PRIORITY_FCP;
ha->isp_ops->nvram_config(vha);
if (ha->fc4_type_priority != FC4_PRIORITY_FCP &&
ha->fc4_type_priority != FC4_PRIORITY_NVME)
ha->fc4_type_priority = FC4_PRIORITY_FCP;
ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n",
ha->fc4_type_priority == FC4_PRIORITY_FCP ? "FCP" : "NVMe");
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
ql_log(ql_log_info, vha, 0x0077,
"Masking HBA WWPN %8phN (via NVRAM).\n", vha->port_name);
return QLA_FUNCTION_FAILED;
}
ql_dbg(ql_dbg_init, vha, 0x0078,
"Verifying loaded RISC code...\n");
/* If smartsan enabled then require fdmi and rdp enabled */
if (ql2xsmartsan) {
ql2xfdmienable = 1;
ql2xrdpenable = 1;
}
if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
rval = ha->isp_ops->chip_diag(vha);
if (rval)
return (rval);
rval = qla2x00_setup_chip(vha);
if (rval)
return (rval);
}
if (IS_QLA84XX(ha)) {
ha->cs84xx = qla84xx_get_chip(vha);
if (!ha->cs84xx) {
ql_log(ql_log_warn, vha, 0x00d0,
"Unable to configure ISP84XX.\n");
return QLA_FUNCTION_FAILED;
}
}
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
if (qla_ini_mode_enabled(vha) || qla_dual_mode_enabled(vha))
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
rval = qla2x00_init_rings(vha);
/* No point in continuing if firmware initialization failed. */
if (rval != QLA_SUCCESS)
return rval;
ha->flags.chip_reset_done = 1;
if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
/* Issue verify 84xx FW IOCB to complete 84xx initialization */
rval = qla84xx_init_chip(vha);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x00d4,
"Unable to initialize ISP84XX.\n");
qla84xx_put_chip(vha);
}
}
/* Load the NIC Core f/w if we are the first protocol driver. */
if (IS_QLA8031(ha)) {
rval = qla83xx_nic_core_fw_load(vha);
if (rval)
ql_log(ql_log_warn, vha, 0x0124,
"Error in initializing NIC Core f/w.\n");
}
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
qla24xx_read_fcp_prio_cfg(vha);
if (IS_P3P_TYPE(ha))
qla82xx_set_driver_version(vha, QLA2XXX_VERSION);
else
qla25xx_set_driver_version(vha, QLA2XXX_VERSION);
return (rval);
}
/**
* qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla2100_pci_config(scsi_qla_host_t *vha)
{
uint16_t w;
unsigned long flags;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
pci_disable_rom(ha->pdev);
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->pci_attr = rd_reg_word(&reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
/**
* qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla2300_pci_config(scsi_qla_host_t *vha)
{
uint16_t w;
unsigned long flags = 0;
uint32_t cnt;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
if (IS_QLA2322(ha) || IS_QLA6322(ha))
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/*
* If this is a 2300 card and not 2312, reset the
* COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
* the 2310 also reports itself as a 2300 so we need to get the
* fb revision level -- a 6 indicates it really is a 2300 and
* not a 2310.
*/
if (IS_QLA2300(ha)) {
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Pause RISC. */
wrt_reg_word(&reg->hccr, HCCR_PAUSE_RISC);
for (cnt = 0; cnt < 30000; cnt++) {
if ((rd_reg_word(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
break;
udelay(10);
}
/* Select FPM registers. */
wrt_reg_word(&reg->ctrl_status, 0x20);
rd_reg_word(&reg->ctrl_status);
/* Get the fb rev level */
ha->fb_rev = RD_FB_CMD_REG(ha, reg);
if (ha->fb_rev == FPM_2300)
pci_clear_mwi(ha->pdev);
/* Deselect FPM registers. */
wrt_reg_word(&reg->ctrl_status, 0x0);
rd_reg_word(&reg->ctrl_status);
/* Release RISC module. */
wrt_reg_word(&reg->hccr, HCCR_RELEASE_RISC);
for (cnt = 0; cnt < 30000; cnt++) {
if ((rd_reg_word(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
break;
udelay(10);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
pci_disable_rom(ha->pdev);
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->pci_attr = rd_reg_word(&reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
/**
* qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla24xx_pci_config(scsi_qla_host_t *vha)
{
uint16_t w;
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
pci_set_master(ha->pdev);
pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
pcix_set_mmrbc(ha->pdev, 2048);
/* PCIe -- adjust Maximum Read Request Size (2048). */
if (pci_is_pcie(ha->pdev))
pcie_set_readrq(ha->pdev, 4096);
pci_disable_rom(ha->pdev);
ha->chip_revision = ha->pdev->revision;
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->pci_attr = rd_reg_dword(&reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
/**
* qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla25xx_pci_config(scsi_qla_host_t *vha)
{
uint16_t w;
struct qla_hw_data *ha = vha->hw;
pci_set_master(ha->pdev);
pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/* PCIe -- adjust Maximum Read Request Size (2048). */
if (pci_is_pcie(ha->pdev))
pcie_set_readrq(ha->pdev, 4096);
pci_disable_rom(ha->pdev);
ha->chip_revision = ha->pdev->revision;
return QLA_SUCCESS;
}
/**
* qla2x00_isp_firmware() - Choose firmware image.
* @vha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_isp_firmware(scsi_qla_host_t *vha)
{
int rval;
uint16_t loop_id, topo, sw_cap;
uint8_t domain, area, al_pa;
struct qla_hw_data *ha = vha->hw;
/* Assume loading risc code */
rval = QLA_FUNCTION_FAILED;
if (ha->flags.disable_risc_code_load) {
ql_log(ql_log_info, vha, 0x0079, "RISC CODE NOT loaded.\n");
/* Verify checksum of loaded RISC code. */
rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
if (rval == QLA_SUCCESS) {
/* And, verify we are not in ROM code. */
rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
&area, &domain, &topo, &sw_cap);
}
}
if (rval)
ql_dbg(ql_dbg_init, vha, 0x007a,
"**** Load RISC code ****.\n");
return (rval);
}
/**
* qla2x00_reset_chip() - Reset ISP chip.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla2x00_reset_chip(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
uint32_t cnt;
uint16_t cmd;
int rval = QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(ha->pdev)))
return rval;
ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Turn off master enable */
cmd = 0;
pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
cmd &= ~PCI_COMMAND_MASTER;
pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
if (!IS_QLA2100(ha)) {
/* Pause RISC. */
wrt_reg_word(&reg->hccr, HCCR_PAUSE_RISC);
if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
for (cnt = 0; cnt < 30000; cnt++) {
if ((rd_reg_word(&reg->hccr) &
HCCR_RISC_PAUSE) != 0)
break;
udelay(100);
}
} else {
rd_reg_word(&reg->hccr); /* PCI Posting. */
udelay(10);
}
/* Select FPM registers. */
wrt_reg_word(&reg->ctrl_status, 0x20);
rd_reg_word(&reg->ctrl_status); /* PCI Posting. */
/* FPM Soft Reset. */
wrt_reg_word(&reg->fpm_diag_config, 0x100);
rd_reg_word(&reg->fpm_diag_config); /* PCI Posting. */
/* Toggle Fpm Reset. */
if (!IS_QLA2200(ha)) {
wrt_reg_word(&reg->fpm_diag_config, 0x0);
rd_reg_word(&reg->fpm_diag_config); /* PCI Posting. */
}
/* Select frame buffer registers. */
wrt_reg_word(&reg->ctrl_status, 0x10);
rd_reg_word(&reg->ctrl_status); /* PCI Posting. */
/* Reset frame buffer FIFOs. */
if (IS_QLA2200(ha)) {
WRT_FB_CMD_REG(ha, reg, 0xa000);
RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
} else {
WRT_FB_CMD_REG(ha, reg, 0x00fc);
/* Read back fb_cmd until zero or 3 seconds max */
for (cnt = 0; cnt < 3000; cnt++) {
if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
break;
udelay(100);
}
}
/* Select RISC module registers. */
wrt_reg_word(&reg->ctrl_status, 0);
rd_reg_word(&reg->ctrl_status); /* PCI Posting. */
/* Reset RISC processor. */
wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
rd_reg_word(&reg->hccr); /* PCI Posting. */
/* Release RISC processor. */
wrt_reg_word(&reg->hccr, HCCR_RELEASE_RISC);
rd_reg_word(&reg->hccr); /* PCI Posting. */
}
wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
wrt_reg_word(&reg->hccr, HCCR_CLR_HOST_INT);
/* Reset ISP chip. */
wrt_reg_word(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
/* Wait for RISC to recover from reset. */
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
/*
* It is necessary to for a delay here since the card doesn't
* respond to PCI reads during a reset. On some architectures
* this will result in an MCA.
*/
udelay(20);
for (cnt = 30000; cnt; cnt--) {
if ((rd_reg_word(&reg->ctrl_status) &
CSR_ISP_SOFT_RESET) == 0)
break;
udelay(100);
}
} else
udelay(10);
/* Reset RISC processor. */
wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
wrt_reg_word(&reg->semaphore, 0);
/* Release RISC processor. */
wrt_reg_word(&reg->hccr, HCCR_RELEASE_RISC);
rd_reg_word(&reg->hccr); /* PCI Posting. */
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
for (cnt = 0; cnt < 30000; cnt++) {
if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
break;
udelay(100);
}
} else
udelay(100);
/* Turn on master enable */
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
/* Disable RISC pause on FPM parity error. */
if (!IS_QLA2100(ha)) {
wrt_reg_word(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
rd_reg_word(&reg->hccr); /* PCI Posting. */
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
/**
* qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC.
* @vha: HA context
*
* Returns 0 on success.
*/
static int
qla81xx_reset_mpi(scsi_qla_host_t *vha)
{
uint16_t mb[4] = {0x1010, 0, 1, 0};
if (!IS_QLA81XX(vha->hw))
return QLA_SUCCESS;
return qla81xx_write_mpi_register(vha, mb);
}
static int
qla_chk_risc_recovery(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
__le16 __iomem *mbptr = &reg->mailbox0;
int i;
u16 mb[32];
int rc = QLA_SUCCESS;
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return rc;
/* this check is only valid after RISC reset */
mb[0] = rd_reg_word(mbptr);
mbptr++;
if (mb[0] == 0xf) {
rc = QLA_FUNCTION_FAILED;
for (i = 1; i < 32; i++) {
mb[i] = rd_reg_word(mbptr);
mbptr++;
}
ql_log(ql_log_warn, vha, 0x1015,
"RISC reset failed. mb[0-7] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n",
mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6], mb[7]);
ql_log(ql_log_warn, vha, 0x1015,
"RISC reset failed. mb[8-15] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n",
mb[8], mb[9], mb[10], mb[11], mb[12], mb[13], mb[14],
mb[15]);
ql_log(ql_log_warn, vha, 0x1015,
"RISC reset failed. mb[16-23] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n",
mb[16], mb[17], mb[18], mb[19], mb[20], mb[21], mb[22],
mb[23]);
ql_log(ql_log_warn, vha, 0x1015,
"RISC reset failed. mb[24-31] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n",
mb[24], mb[25], mb[26], mb[27], mb[28], mb[29], mb[30],
mb[31]);
}
return rc;
}
/**
* qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
* @vha: HA context
*
* Returns 0 on success.
*/
static inline int
qla24xx_reset_risc(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t cnt;
uint16_t wd;
static int abts_cnt; /* ISP abort retry counts */
int rval = QLA_SUCCESS;
int print = 1;
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Reset RISC. */
wrt_reg_dword(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
for (cnt = 0; cnt < 30000; cnt++) {
if ((rd_reg_dword(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
break;
udelay(10);
}
if (!(rd_reg_dword(&reg->ctrl_status) & CSRX_DMA_ACTIVE))
set_bit(DMA_SHUTDOWN_CMPL, &ha->fw_dump_cap_flags);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x017e,
"HCCR: 0x%x, Control Status %x, DMA active status:0x%x\n",
rd_reg_dword(&reg->hccr),
rd_reg_dword(&reg->ctrl_status),
(rd_reg_dword(&reg->ctrl_status) & CSRX_DMA_ACTIVE));
wrt_reg_dword(&reg->ctrl_status,
CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
udelay(100);
/* Wait for firmware to complete NVRAM accesses. */
rd_reg_word(&reg->mailbox0);
for (cnt = 10000; rd_reg_word(&reg->mailbox0) != 0 &&
rval == QLA_SUCCESS; cnt--) {
barrier();
if (cnt)
udelay(5);
else
rval = QLA_FUNCTION_TIMEOUT;
}
if (rval == QLA_SUCCESS)
set_bit(ISP_MBX_RDY, &ha->fw_dump_cap_flags);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x017f,
"HCCR: 0x%x, MailBox0 Status 0x%x\n",
rd_reg_dword(&reg->hccr),
rd_reg_word(&reg->mailbox0));
/* Wait for soft-reset to complete. */
rd_reg_dword(&reg->ctrl_status);
for (cnt = 0; cnt < 60; cnt++) {
barrier();
if ((rd_reg_dword(&reg->ctrl_status) &
CSRX_ISP_SOFT_RESET) == 0)
break;
udelay(5);
}
if (!(rd_reg_dword(&reg->ctrl_status) & CSRX_ISP_SOFT_RESET))
set_bit(ISP_SOFT_RESET_CMPL, &ha->fw_dump_cap_flags);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x015d,
"HCCR: 0x%x, Soft Reset status: 0x%x\n",
rd_reg_dword(&reg->hccr),
rd_reg_dword(&reg->ctrl_status));
/* If required, do an MPI FW reset now */
if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) {
if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) {
if (++abts_cnt < 5) {
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
set_bit(MPI_RESET_NEEDED, &vha->dpc_flags);
} else {
/*
* We exhausted the ISP abort retries. We have to
* set the board offline.
*/
abts_cnt = 0;
vha->flags.online = 0;
}
}
}
wrt_reg_dword(&reg->hccr, HCCRX_SET_RISC_RESET);
rd_reg_dword(&reg->hccr);
wrt_reg_dword(&reg->hccr, HCCRX_REL_RISC_PAUSE);
rd_reg_dword(&reg->hccr);
wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_RESET);
mdelay(10);
rd_reg_dword(&reg->hccr);
wd = rd_reg_word(&reg->mailbox0);
for (cnt = 300; wd != 0 && rval == QLA_SUCCESS; cnt--) {
barrier();
if (cnt) {
mdelay(1);
if (print && qla_chk_risc_recovery(vha))
print = 0;
wd = rd_reg_word(&reg->mailbox0);
} else {
rval = QLA_FUNCTION_TIMEOUT;
ql_log(ql_log_warn, vha, 0x015e,
"RISC reset timeout\n");
}
}
if (rval == QLA_SUCCESS)
set_bit(RISC_RDY_AFT_RESET, &ha->fw_dump_cap_flags);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x015e,
"Host Risc 0x%x, mailbox0 0x%x\n",
rd_reg_dword(&reg->hccr),
rd_reg_word(&reg->mailbox0));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x015f,
"Driver in %s mode\n",
IS_NOPOLLING_TYPE(ha) ? "Interrupt" : "Polling");
if (IS_NOPOLLING_TYPE(ha))
ha->isp_ops->enable_intrs(ha);
return rval;
}
static void
qla25xx_read_risc_sema_reg(scsi_qla_host_t *vha, uint32_t *data)
{
struct device_reg_24xx __iomem *reg = &vha->hw->iobase->isp24;
wrt_reg_dword(&reg->iobase_addr, RISC_REGISTER_BASE_OFFSET);
*data = rd_reg_dword(&reg->iobase_window + RISC_REGISTER_WINDOW_OFFSET);
}
static void
qla25xx_write_risc_sema_reg(scsi_qla_host_t *vha, uint32_t data)
{
struct device_reg_24xx __iomem *reg = &vha->hw->iobase->isp24;
wrt_reg_dword(&reg->iobase_addr, RISC_REGISTER_BASE_OFFSET);
wrt_reg_dword(&reg->iobase_window + RISC_REGISTER_WINDOW_OFFSET, data);
}
static void
qla25xx_manipulate_risc_semaphore(scsi_qla_host_t *vha)
{
uint32_t wd32 = 0;
uint delta_msec = 100;
uint elapsed_msec = 0;
uint timeout_msec;
ulong n;
if (vha->hw->pdev->subsystem_device != 0x0175 &&
vha->hw->pdev->subsystem_device != 0x0240)
return;
wrt_reg_dword(&vha->hw->iobase->isp24.hccr, HCCRX_SET_RISC_PAUSE);
udelay(100);
attempt:
timeout_msec = TIMEOUT_SEMAPHORE;
n = timeout_msec / delta_msec;
while (n--) {
qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_SET);
qla25xx_read_risc_sema_reg(vha, &wd32);
if (wd32 & RISC_SEMAPHORE)
break;
msleep(delta_msec);
elapsed_msec += delta_msec;
if (elapsed_msec > TIMEOUT_TOTAL_ELAPSED)
goto force;
}
if (!(wd32 & RISC_SEMAPHORE))
goto force;
if (!(wd32 & RISC_SEMAPHORE_FORCE))
goto acquired;
qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_CLR);
timeout_msec = TIMEOUT_SEMAPHORE_FORCE;
n = timeout_msec / delta_msec;
while (n--) {
qla25xx_read_risc_sema_reg(vha, &wd32);
if (!(wd32 & RISC_SEMAPHORE_FORCE))
break;
msleep(delta_msec);
elapsed_msec += delta_msec;
if (elapsed_msec > TIMEOUT_TOTAL_ELAPSED)
goto force;
}
if (wd32 & RISC_SEMAPHORE_FORCE)
qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_FORCE_CLR);
goto attempt;
force:
qla25xx_write_risc_sema_reg(vha, RISC_SEMAPHORE_FORCE_SET);
acquired:
return;
}
/**
* qla24xx_reset_chip() - Reset ISP24xx chip.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla24xx_reset_chip(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
int rval = QLA_FUNCTION_FAILED;
if (pci_channel_offline(ha->pdev) &&
ha->flags.pci_channel_io_perm_failure) {
return rval;
}
ha->isp_ops->disable_intrs(ha);
qla25xx_manipulate_risc_semaphore(vha);
/* Perform RISC reset. */
rval = qla24xx_reset_risc(vha);
return rval;
}
/**
* qla2x00_chip_diag() - Test chip for proper operation.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla2x00_chip_diag(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
unsigned long flags = 0;
uint16_t data;
uint32_t cnt;
uint16_t mb[5];
struct req_que *req = ha->req_q_map[0];
/* Assume a failed state */
rval = QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_init, vha, 0x007b, "Testing device at %p.\n",
&reg->flash_address);
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Reset ISP chip. */
wrt_reg_word(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
/*
* We need to have a delay here since the card will not respond while
* in reset causing an MCA on some architectures.
*/
udelay(20);
data = qla2x00_debounce_register(&reg->ctrl_status);
for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
udelay(5);
data = rd_reg_word(&reg->ctrl_status);
barrier();
}
if (!cnt)
goto chip_diag_failed;
ql_dbg(ql_dbg_init, vha, 0x007c,
"Reset register cleared by chip reset.\n");
/* Reset RISC processor. */
wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
wrt_reg_word(&reg->hccr, HCCR_RELEASE_RISC);
/* Workaround for QLA2312 PCI parity error */
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
udelay(5);
data = RD_MAILBOX_REG(ha, reg, 0);
barrier();
}
} else
udelay(10);
if (!cnt)
goto chip_diag_failed;
/* Check product ID of chip */
ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product ID of chip.\n");
mb[1] = RD_MAILBOX_REG(ha, reg, 1);
mb[2] = RD_MAILBOX_REG(ha, reg, 2);
mb[3] = RD_MAILBOX_REG(ha, reg, 3);
mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
mb[3] != PROD_ID_3) {
ql_log(ql_log_warn, vha, 0x0062,
"Wrong product ID = 0x%x,0x%x,0x%x.\n",
mb[1], mb[2], mb[3]);
goto chip_diag_failed;
}
ha->product_id[0] = mb[1];
ha->product_id[1] = mb[2];
ha->product_id[2] = mb[3];
ha->product_id[3] = mb[4];
/* Adjust fw RISC transfer size */
if (req->length > 1024)
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
else
ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
req->length;
if (IS_QLA2200(ha) &&
RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
/* Limit firmware transfer size with a 2200A */
ql_dbg(ql_dbg_init, vha, 0x007e, "Found QLA2200A Chip.\n");
ha->device_type |= DT_ISP2200A;
ha->fw_transfer_size = 128;
}
/* Wrap Incoming Mailboxes Test. */
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ql_dbg(ql_dbg_init, vha, 0x007f, "Checking mailboxes.\n");
rval = qla2x00_mbx_reg_test(vha);
if (rval)
ql_log(ql_log_warn, vha, 0x0080,
"Failed mailbox send register test.\n");
else
/* Flag a successful rval */
rval = QLA_SUCCESS;
spin_lock_irqsave(&ha->hardware_lock, flags);
chip_diag_failed:
if (rval)
ql_log(ql_log_info, vha, 0x0081,
"Chip diagnostics **** FAILED ****.\n");
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (rval);
}
/**
* qla24xx_chip_diag() - Test ISP24xx for proper operation.
* @vha: HA context
*
* Returns 0 on success.
*/
int
qla24xx_chip_diag(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
if (IS_P3P_TYPE(ha))
return QLA_SUCCESS;
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
rval = qla2x00_mbx_reg_test(vha);
if (rval) {
ql_log(ql_log_warn, vha, 0x0082,
"Failed mailbox send register test.\n");
} else {
/* Flag a successful rval */
rval = QLA_SUCCESS;
}
return rval;
}
static void
qla2x00_init_fce_trace(scsi_qla_host_t *vha)
{
int rval;
dma_addr_t tc_dma;
void *tc;
struct qla_hw_data *ha = vha->hw;
if (!IS_FWI2_CAPABLE(ha))
return;
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return;
if (ha->fce) {
ql_dbg(ql_dbg_init, vha, 0x00bd,
"%s: FCE Mem is already allocated.\n",
__func__);
return;
}
/* Allocate memory for Fibre Channel Event Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
GFP_KERNEL);
if (!tc) {
ql_log(ql_log_warn, vha, 0x00be,
"Unable to allocate (%d KB) for FCE.\n",
FCE_SIZE / 1024);
return;
}
rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
ha->fce_mb, &ha->fce_bufs);
if (rval) {
ql_log(ql_log_warn, vha, 0x00bf,
"Unable to initialize FCE (%d).\n", rval);
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, tc_dma);
return;
}
ql_dbg(ql_dbg_init, vha, 0x00c0,
"Allocated (%d KB) for FCE...\n", FCE_SIZE / 1024);
ha->flags.fce_enabled = 1;
ha->fce_dma = tc_dma;
ha->fce = tc;
}
static void
qla2x00_init_eft_trace(scsi_qla_host_t *vha)
{
int rval;
dma_addr_t tc_dma;
void *tc;
struct qla_hw_data *ha = vha->hw;
if (!IS_FWI2_CAPABLE(ha))
return;
if (ha->eft) {
ql_dbg(ql_dbg_init, vha, 0x00bd,
"%s: EFT Mem is already allocated.\n",
__func__);
return;
}
/* Allocate memory for Extended Trace Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
GFP_KERNEL);
if (!tc) {
ql_log(ql_log_warn, vha, 0x00c1,
"Unable to allocate (%d KB) for EFT.\n",
EFT_SIZE / 1024);
return;
}
rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
if (rval) {
ql_log(ql_log_warn, vha, 0x00c2,
"Unable to initialize EFT (%d).\n", rval);
dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, tc_dma);
return;
}
ql_dbg(ql_dbg_init, vha, 0x00c3,
"Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
ha->eft_dma = tc_dma;
ha->eft = tc;
}
static void
qla2x00_alloc_offload_mem(scsi_qla_host_t *vha)
{
qla2x00_init_fce_trace(vha);
qla2x00_init_eft_trace(vha);
}
void
qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
{
uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
eft_size, fce_size, mq_size;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
struct qla2xxx_fw_dump *fw_dump;
if (ha->fw_dump) {
ql_dbg(ql_dbg_init, vha, 0x00bd,
"Firmware dump already allocated.\n");
return;
}
ha->fw_dumped = 0;
ha->fw_dump_cap_flags = 0;
dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
req_q_size = rsp_q_size = 0;
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
fixed_size = sizeof(struct qla2100_fw_dump);
} else if (IS_QLA23XX(ha)) {
fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
} else if (IS_FWI2_CAPABLE(ha)) {
if (IS_QLA83XX(ha))
fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
else if (IS_QLA81XX(ha))
fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
else if (IS_QLA25XX(ha))
fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
else
fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
if (ha->mqenable) {
if (!IS_QLA83XX(ha))
mq_size = sizeof(struct qla2xxx_mq_chain);
/*
* Allocate maximum buffer size for all queues - Q0.
* Resizing must be done at end-of-dump processing.
*/
mq_size += (ha->max_req_queues - 1) *
(req->length * sizeof(request_t));
mq_size += (ha->max_rsp_queues - 1) *
(rsp->length * sizeof(response_t));
}
if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
qla2x00_init_fce_trace(vha);
if (ha->fce)
fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
qla2x00_init_eft_trace(vha);
if (ha->eft)
eft_size = EFT_SIZE;
}
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
struct fwdt *fwdt = ha->fwdt;
uint j;
for (j = 0; j < 2; j++, fwdt++) {
if (!fwdt->template) {
ql_dbg(ql_dbg_init, vha, 0x00ba,
"-> fwdt%u no template\n", j);
continue;
}
ql_dbg(ql_dbg_init, vha, 0x00fa,
"-> fwdt%u calculating fwdump size...\n", j);
fwdt->dump_size = qla27xx_fwdt_calculate_dump_size(
vha, fwdt->template);
ql_dbg(ql_dbg_init, vha, 0x00fa,
"-> fwdt%u calculated fwdump size = %#lx bytes\n",
j, fwdt->dump_size);
dump_size += fwdt->dump_size;
}
/* Add space for spare MPI fw dump. */
dump_size += ha->fwdt[1].dump_size;
} else {
req_q_size = req->length * sizeof(request_t);
rsp_q_size = rsp->length * sizeof(response_t);
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size
+ eft_size;
ha->chain_offset = dump_size;
dump_size += mq_size + fce_size;
if (ha->exchoffld_buf)
dump_size += sizeof(struct qla2xxx_offld_chain) +
ha->exchoffld_size;
if (ha->exlogin_buf)
dump_size += sizeof(struct qla2xxx_offld_chain) +
ha->exlogin_size;
}
if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) {
ql_dbg(ql_dbg_init, vha, 0x00c5,
"%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n",
__func__, dump_size, ha->fw_dump_len,
ha->fw_dump_alloc_len);
fw_dump = vmalloc(dump_size);
if (!fw_dump) {
ql_log(ql_log_warn, vha, 0x00c4,
"Unable to allocate (%d KB) for firmware dump.\n",
dump_size / 1024);
} else {
mutex_lock(&ha->optrom_mutex);
if (ha->fw_dumped) {
memcpy(fw_dump, ha->fw_dump, ha->fw_dump_len);
vfree(ha->fw_dump);
ha->fw_dump = fw_dump;
ha->fw_dump_alloc_len = dump_size;
ql_dbg(ql_dbg_init, vha, 0x00c5,
"Re-Allocated (%d KB) and save firmware dump.\n",
dump_size / 1024);
} else {
vfree(ha->fw_dump);
ha->fw_dump = fw_dump;
ha->fw_dump_len = ha->fw_dump_alloc_len =
dump_size;
ql_dbg(ql_dbg_init, vha, 0x00c5,
"Allocated (%d KB) for firmware dump.\n",
dump_size / 1024);
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
ha->mpi_fw_dump = (char *)fw_dump +
ha->fwdt[1].dump_size;
mutex_unlock(&ha->optrom_mutex);
return;
}
ha->fw_dump->signature[0] = 'Q';
ha->fw_dump->signature[1] = 'L';
ha->fw_dump->signature[2] = 'G';
ha->fw_dump->signature[3] = 'C';
ha->fw_dump->version = htonl(1);
ha->fw_dump->fixed_size = htonl(fixed_size);
ha->fw_dump->mem_size = htonl(mem_size);
ha->fw_dump->req_q_size = htonl(req_q_size);
ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
ha->fw_dump->eft_size = htonl(eft_size);
ha->fw_dump->eft_addr_l =
htonl(LSD(ha->eft_dma));
ha->fw_dump->eft_addr_h =
htonl(MSD(ha->eft_dma));
ha->fw_dump->header_size =
htonl(offsetof
(struct qla2xxx_fw_dump, isp));
}
mutex_unlock(&ha->optrom_mutex);
}
}
}
static int
qla81xx_mpi_sync(scsi_qla_host_t *vha)
{
#define MPS_MASK 0xe0
int rval;
uint16_t dc;
uint32_t dw;
if (!IS_QLA81XX(vha->hw))
return QLA_SUCCESS;
rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x0105,
"Unable to acquire semaphore.\n");
goto done;
}
pci_read_config_word(vha->hw->pdev, 0x54, &dc);
rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x0067, "Unable to read sync.\n");
goto done_release;
}
dc &= MPS_MASK;
if (dc == (dw & MPS_MASK))
goto done_release;
dw &= ~MPS_MASK;
dw |= dc;
rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x0114, "Unable to gain sync.\n");
}
done_release:
rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x006d,
"Unable to release semaphore.\n");
}
done:
return rval;
}
int
qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
{
/* Don't try to reallocate the array */
if (req->outstanding_cmds)
return QLA_SUCCESS;
if (!IS_FWI2_CAPABLE(ha))
req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
else {
if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
req->num_outstanding_cmds = ha->cur_fw_xcb_count;
else
req->num_outstanding_cmds = ha->cur_fw_iocb_count;
}
treewide: kzalloc() -> kcalloc() The kzalloc() function has a 2-factor argument form, kcalloc(). This patch replaces cases of: kzalloc(a * b, gfp) with: kcalloc(a * b, gfp) as well as handling cases of: kzalloc(a * b * c, gfp) with: kzalloc(array3_size(a, b, c), gfp) as it's slightly less ugly than: kzalloc_array(array_size(a, b), c, gfp) This does, however, attempt to ignore constant size factors like: kzalloc(4 * 1024, gfp) though any constants defined via macros get caught up in the conversion. Any factors with a sizeof() of "unsigned char", "char", and "u8" were dropped, since they're redundant. The Coccinelle script used for this was: // Fix redundant parens around sizeof(). @@ type TYPE; expression THING, E; @@ ( kzalloc( - (sizeof(TYPE)) * E + sizeof(TYPE) * E , ...) | kzalloc( - (sizeof(THING)) * E + sizeof(THING) * E , ...) ) // Drop single-byte sizes and redundant parens. @@ expression COUNT; typedef u8; typedef __u8; @@ ( kzalloc( - sizeof(u8) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(__u8) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(char) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(unsigned char) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(u8) * COUNT + COUNT , ...) | kzalloc( - sizeof(__u8) * COUNT + COUNT , ...) | kzalloc( - sizeof(char) * COUNT + COUNT , ...) | kzalloc( - sizeof(unsigned char) * COUNT + COUNT , ...) ) // 2-factor product with sizeof(type/expression) and identifier or constant. @@ type TYPE; expression THING; identifier COUNT_ID; constant COUNT_CONST; @@ ( - kzalloc + kcalloc ( - sizeof(TYPE) * (COUNT_ID) + COUNT_ID, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * COUNT_ID + COUNT_ID, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * (COUNT_CONST) + COUNT_CONST, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * COUNT_CONST + COUNT_CONST, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (COUNT_ID) + COUNT_ID, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * COUNT_ID + COUNT_ID, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (COUNT_CONST) + COUNT_CONST, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * COUNT_CONST + COUNT_CONST, sizeof(THING) , ...) ) // 2-factor product, only identifiers. @@ identifier SIZE, COUNT; @@ - kzalloc + kcalloc ( - SIZE * COUNT + COUNT, SIZE , ...) // 3-factor product with 1 sizeof(type) or sizeof(expression), with // redundant parens removed. @@ expression THING; identifier STRIDE, COUNT; type TYPE; @@ ( kzalloc( - sizeof(TYPE) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(THING) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) ) // 3-factor product with 2 sizeof(variable), with redundant parens removed. @@ expression THING1, THING2; identifier COUNT; type TYPE1, TYPE2; @@ ( kzalloc( - sizeof(TYPE1) * sizeof(TYPE2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kzalloc( - sizeof(THING1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kzalloc( - sizeof(THING1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) ) // 3-factor product, only identifiers, with redundant parens removed. @@ identifier STRIDE, SIZE, COUNT; @@ ( kzalloc( - (COUNT) * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) ) // Any remaining multi-factor products, first at least 3-factor products, // when they're not all constants... @@ expression E1, E2, E3; constant C1, C2, C3; @@ ( kzalloc(C1 * C2 * C3, ...) | kzalloc( - (E1) * E2 * E3 + array3_size(E1, E2, E3) , ...) | kzalloc( - (E1) * (E2) * E3 + array3_size(E1, E2, E3) , ...) | kzalloc( - (E1) * (E2) * (E3) + array3_size(E1, E2, E3) , ...) | kzalloc( - E1 * E2 * E3 + array3_size(E1, E2, E3) , ...) ) // And then all remaining 2 factors products when they're not all constants, // keeping sizeof() as the second factor argument. @@ expression THING, E1, E2; type TYPE; constant C1, C2, C3; @@ ( kzalloc(sizeof(THING) * C2, ...) | kzalloc(sizeof(TYPE) * C2, ...) | kzalloc(C1 * C2 * C3, ...) | kzalloc(C1 * C2, ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * (E2) + E2, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * E2 + E2, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (E2) + E2, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * E2 + E2, sizeof(THING) , ...) | - kzalloc + kcalloc ( - (E1) * E2 + E1, E2 , ...) | - kzalloc + kcalloc ( - (E1) * (E2) + E1, E2 , ...) | - kzalloc + kcalloc ( - E1 * E2 + E1, E2 , ...) ) Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
req->outstanding_cmds = kcalloc(req->num_outstanding_cmds,
sizeof(srb_t *),
GFP_KERNEL);
if (!req->outstanding_cmds) {
/*
* Try to allocate a minimal size just so we can get through
* initialization.
*/
req->num_outstanding_cmds = MIN_OUTSTANDING_COMMANDS;
treewide: kzalloc() -> kcalloc() The kzalloc() function has a 2-factor argument form, kcalloc(). This patch replaces cases of: kzalloc(a * b, gfp) with: kcalloc(a * b, gfp) as well as handling cases of: kzalloc(a * b * c, gfp) with: kzalloc(array3_size(a, b, c), gfp) as it's slightly less ugly than: kzalloc_array(array_size(a, b), c, gfp) This does, however, attempt to ignore constant size factors like: kzalloc(4 * 1024, gfp) though any constants defined via macros get caught up in the conversion. Any factors with a sizeof() of "unsigned char", "char", and "u8" were dropped, since they're redundant. The Coccinelle script used for this was: // Fix redundant parens around sizeof(). @@ type TYPE; expression THING, E; @@ ( kzalloc( - (sizeof(TYPE)) * E + sizeof(TYPE) * E , ...) | kzalloc( - (sizeof(THING)) * E + sizeof(THING) * E , ...) ) // Drop single-byte sizes and redundant parens. @@ expression COUNT; typedef u8; typedef __u8; @@ ( kzalloc( - sizeof(u8) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(__u8) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(char) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(unsigned char) * (COUNT) + COUNT , ...) | kzalloc( - sizeof(u8) * COUNT + COUNT , ...) | kzalloc( - sizeof(__u8) * COUNT + COUNT , ...) | kzalloc( - sizeof(char) * COUNT + COUNT , ...) | kzalloc( - sizeof(unsigned char) * COUNT + COUNT , ...) ) // 2-factor product with sizeof(type/expression) and identifier or constant. @@ type TYPE; expression THING; identifier COUNT_ID; constant COUNT_CONST; @@ ( - kzalloc + kcalloc ( - sizeof(TYPE) * (COUNT_ID) + COUNT_ID, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * COUNT_ID + COUNT_ID, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * (COUNT_CONST) + COUNT_CONST, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * COUNT_CONST + COUNT_CONST, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (COUNT_ID) + COUNT_ID, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * COUNT_ID + COUNT_ID, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (COUNT_CONST) + COUNT_CONST, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * COUNT_CONST + COUNT_CONST, sizeof(THING) , ...) ) // 2-factor product, only identifiers. @@ identifier SIZE, COUNT; @@ - kzalloc + kcalloc ( - SIZE * COUNT + COUNT, SIZE , ...) // 3-factor product with 1 sizeof(type) or sizeof(expression), with // redundant parens removed. @@ expression THING; identifier STRIDE, COUNT; type TYPE; @@ ( kzalloc( - sizeof(TYPE) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(TYPE) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kzalloc( - sizeof(THING) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kzalloc( - sizeof(THING) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) ) // 3-factor product with 2 sizeof(variable), with redundant parens removed. @@ expression THING1, THING2; identifier COUNT; type TYPE1, TYPE2; @@ ( kzalloc( - sizeof(TYPE1) * sizeof(TYPE2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kzalloc( - sizeof(THING1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kzalloc( - sizeof(THING1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) | kzalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) ) // 3-factor product, only identifiers, with redundant parens removed. @@ identifier STRIDE, SIZE, COUNT; @@ ( kzalloc( - (COUNT) * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - (COUNT) * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kzalloc( - COUNT * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) ) // Any remaining multi-factor products, first at least 3-factor products, // when they're not all constants... @@ expression E1, E2, E3; constant C1, C2, C3; @@ ( kzalloc(C1 * C2 * C3, ...) | kzalloc( - (E1) * E2 * E3 + array3_size(E1, E2, E3) , ...) | kzalloc( - (E1) * (E2) * E3 + array3_size(E1, E2, E3) , ...) | kzalloc( - (E1) * (E2) * (E3) + array3_size(E1, E2, E3) , ...) | kzalloc( - E1 * E2 * E3 + array3_size(E1, E2, E3) , ...) ) // And then all remaining 2 factors products when they're not all constants, // keeping sizeof() as the second factor argument. @@ expression THING, E1, E2; type TYPE; constant C1, C2, C3; @@ ( kzalloc(sizeof(THING) * C2, ...) | kzalloc(sizeof(TYPE) * C2, ...) | kzalloc(C1 * C2 * C3, ...) | kzalloc(C1 * C2, ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * (E2) + E2, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(TYPE) * E2 + E2, sizeof(TYPE) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * (E2) + E2, sizeof(THING) , ...) | - kzalloc + kcalloc ( - sizeof(THING) * E2 + E2, sizeof(THING) , ...) | - kzalloc + kcalloc ( - (E1) * E2 + E1, E2 , ...) | - kzalloc + kcalloc ( - (E1) * (E2) + E1, E2 , ...) | - kzalloc + kcalloc ( - E1 * E2 + E1, E2 , ...) ) Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
req->outstanding_cmds = kcalloc(req->num_outstanding_cmds,
sizeof(srb_t *),
GFP_KERNEL);
if (!req->outstanding_cmds) {
ql_log(ql_log_fatal, NULL, 0x0126,
"Failed to allocate memory for "
"outstanding_cmds for req_que %p.\n", req);
req->num_outstanding_cmds = 0;
return QLA_FUNCTION_FAILED;
}
}
return QLA_SUCCESS;
}
#define PRINT_FIELD(_field, _flag, _str) { \
if (a0->_field & _flag) {\
if (p) {\
strcat(ptr, "|");\
ptr++;\
leftover--;\
} \
len = snprintf(ptr, leftover, "%s", _str); \
p = 1;\
leftover -= len;\
ptr += len; \
} \
}
static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha)
{
#define STR_LEN 64
struct sff_8247_a0 *a0 = (struct sff_8247_a0 *)vha->hw->sfp_data;
u8 str[STR_LEN], *ptr, p;
int leftover, len;
memset(str, 0, STR_LEN);
snprintf(str, SFF_VEN_NAME_LEN+1, a0->vendor_name);
ql_dbg(ql_dbg_init, vha, 0x015a,
"SFP MFG Name: %s\n", str);
memset(str, 0, STR_LEN);
snprintf(str, SFF_PART_NAME_LEN+1, a0->vendor_pn);
ql_dbg(ql_dbg_init, vha, 0x015c,
"SFP Part Name: %s\n", str);
/* media */
memset(str, 0, STR_LEN);
ptr = str;
leftover = STR_LEN;
p = len = 0;
PRINT_FIELD(fc_med_cc9, FC_MED_TW, "Twin AX");
PRINT_FIELD(fc_med_cc9, FC_MED_TP, "Twisted Pair");
PRINT_FIELD(fc_med_cc9, FC_MED_MI, "Min Coax");
PRINT_FIELD(fc_med_cc9, FC_MED_TV, "Video Coax");
PRINT_FIELD(fc_med_cc9, FC_MED_M6, "MultiMode 62.5um");
PRINT_FIELD(fc_med_cc9, FC_MED_M5, "MultiMode 50um");
PRINT_FIELD(fc_med_cc9, FC_MED_SM, "SingleMode");
ql_dbg(ql_dbg_init, vha, 0x0160,
"SFP Media: %s\n", str);
/* link length */
memset(str, 0, STR_LEN);
ptr = str;
leftover = STR_LEN;
p = len = 0;
PRINT_FIELD(fc_ll_cc7, FC_LL_VL, "Very Long");
PRINT_FIELD(fc_ll_cc7, FC_LL_S, "Short");
PRINT_FIELD(fc_ll_cc7, FC_LL_I, "Intermediate");
PRINT_FIELD(fc_ll_cc7, FC_LL_L, "Long");
PRINT_FIELD(fc_ll_cc7, FC_LL_M, "Medium");
ql_dbg(ql_dbg_init, vha, 0x0196,
"SFP Link Length: %s\n", str);
memset(str, 0, STR_LEN);
ptr = str;
leftover = STR_LEN;
p = len = 0;
PRINT_FIELD(fc_ll_cc7, FC_LL_SA, "Short Wave (SA)");
PRINT_FIELD(fc_ll_cc7, FC_LL_LC, "Long Wave(LC)");
PRINT_FIELD(fc_tec_cc8, FC_TEC_SN, "Short Wave (SN)");
PRINT_FIELD(fc_tec_cc8, FC_TEC_SL, "Short Wave (SL)");
PRINT_FIELD(fc_tec_cc8, FC_TEC_LL, "Long Wave (LL)");
ql_dbg(ql_dbg_init, vha, 0x016e,
"SFP FC Link Tech: %s\n", str);
if (a0->length_km)
ql_dbg(ql_dbg_init, vha, 0x016f,
"SFP Distant: %d km\n", a0->length_km);
if (a0->length_100m)
ql_dbg(ql_dbg_init, vha, 0x0170,
"SFP Distant: %d m\n", a0->length_100m*100);
if (a0->length_50um_10m)
ql_dbg(ql_dbg_init, vha, 0x0189,
"SFP Distant (WL=50um): %d m\n", a0->length_50um_10m * 10);
if (a0->length_62um_10m)
ql_dbg(ql_dbg_init, vha, 0x018a,
"SFP Distant (WL=62.5um): %d m\n", a0->length_62um_10m * 10);
if (a0->length_om4_10m)
ql_dbg(ql_dbg_init, vha, 0x0194,
"SFP Distant (OM4): %d m\n", a0->length_om4_10m * 10);
if (a0->length_om3_10m)
ql_dbg(ql_dbg_init, vha, 0x0195,
"SFP Distant (OM3): %d m\n", a0->length_om3_10m * 10);
}
/**
* qla24xx_detect_sfp()
*
* @vha: adapter state pointer.
*
* @return
* 0 -- Configure firmware to use short-range settings -- normal
* buffer-to-buffer credits.
*
* 1 -- Configure firmware to use long-range settings -- extra
* buffer-to-buffer credits should be allocated with
* ha->lr_distance containing distance settings from NVRAM or SFP
* (if supported).
*/
int
qla24xx_detect_sfp(scsi_qla_host_t *vha)
{
int rc, used_nvram;
struct sff_8247_a0 *a;
struct qla_hw_data *ha = vha->hw;
struct nvram_81xx *nv = ha->nvram;
#define LR_DISTANCE_UNKNOWN 2
static const char * const types[] = { "Short", "Long" };
static const char * const lengths[] = { "(10km)", "(5km)", "" };
u8 ll = 0;
/* Seed with NVRAM settings. */
used_nvram = 0;
ha->flags.lr_detected = 0;
if (IS_BPM_RANGE_CAPABLE(ha) &&
(nv->enhanced_features & NEF_LR_DIST_ENABLE)) {
used_nvram = 1;
ha->flags.lr_detected = 1;
ha->lr_distance =
(nv->enhanced_features >> LR_DIST_NV_POS)
& LR_DIST_NV_MASK;
}
if (!IS_BPM_ENABLED(vha))
goto out;
/* Determine SR/LR capabilities of SFP/Transceiver. */
rc = qla2x00_read_sfp_dev(vha, NULL, 0);
if (rc)
goto out;
used_nvram = 0;
a = (struct sff_8247_a0 *)vha->hw->sfp_data;
qla2xxx_print_sfp_info(vha);
ha->flags.lr_detected = 0;
ll = a->fc_ll_cc7;
if (ll & FC_LL_VL || ll & FC_LL_L) {
/* Long range, track length. */
ha->flags.lr_detected = 1;
if (a->length_km > 5 || a->length_100m > 50)
ha->lr_distance = LR_DISTANCE_10K;
else
ha->lr_distance = LR_DISTANCE_5K;
}
out:
ql_dbg(ql_dbg_async, vha, 0x507b,
"SFP detect: %s-Range SFP %s (nvr=%x ll=%x lr=%x lrd=%x).\n",
types[ha->flags.lr_detected],
ha->flags.lr_detected ? lengths[ha->lr_distance] :
lengths[LR_DISTANCE_UNKNOWN],
used_nvram, ll, ha->flags.lr_detected, ha->lr_distance);
return ha->flags.lr_detected;
}
void qla_init_iocb_limit(scsi_qla_host_t *vha)
{
u16 i, num_qps;
u32 limit;
struct qla_hw_data *ha = vha->hw;
num_qps = ha->num_qpairs + 1;
limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100;
ha->base_qpair->fwres.iocbs_total = ha->orig_fw_iocb_count;
ha->base_qpair->fwres.iocbs_limit = limit;
ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps;
ha->base_qpair->fwres.iocbs_used = 0;
ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count;
ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count *
QLA_IOCB_PCT_LIMIT) / 100;
ha->base_qpair->fwres.exch_used = 0;
for (i = 0; i < ha->max_qpairs; i++) {
if (ha->queue_pair_map[i]) {
ha->queue_pair_map[i]->fwres.iocbs_total =
ha->orig_fw_iocb_count;
ha->queue_pair_map[i]->fwres.iocbs_limit = limit;
ha->queue_pair_map[i]->fwres.iocbs_qp_limit =
limit / num_qps;
ha->queue_pair_map[i]->fwres.iocbs_used = 0;
ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count;
ha->queue_pair_map[i]->fwres.exch_limit =
(ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100;
ha->queue_pair_map[i]->fwres.exch_used = 0;
}
}
}
/**
* qla2x00_setup_chip() - Load and start RISC firmware.
* @vha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_setup_chip(scsi_qla_host_t *vha)
{
int rval;
uint32_t srisc_address = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
unsigned long flags;
uint16_t fw_major_version;
int done_once = 0;
if (IS_P3P_TYPE(ha)) {
rval = ha->isp_ops->load_risc(vha, &srisc_address);
if (rval == QLA_SUCCESS) {
qla2x00_stop_firmware(vha);
goto enable_82xx_npiv;
} else
goto failed;
}
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
/* Disable SRAM, Instruction RAM and GP RAM parity. */
spin_lock_irqsave(&ha->hardware_lock, flags);
wrt_reg_word(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
rd_reg_word(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
qla81xx_mpi_sync(vha);
execute_fw_with_lr:
/* Load firmware sequences */
rval = ha->isp_ops->load_risc(vha, &srisc_address);
if (rval == QLA_SUCCESS) {
ql_dbg(ql_dbg_init, vha, 0x00c9,
"Verifying Checksum of loaded RISC code.\n");
rval = qla2x00_verify_checksum(vha, srisc_address);
if (rval == QLA_SUCCESS) {
/* Start firmware execution. */
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Starting firmware.\n");
if (ql2xexlogins)
ha->flags.exlogins_enabled = 1;
if (qla_is_exch_offld_enabled(vha))
ha->flags.exchoffld_enabled = 1;
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
/* Enable BPM support? */
if (!done_once++ && qla24xx_detect_sfp(vha)) {
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Re-starting firmware -- BPM.\n");
/* Best-effort - re-init. */
ha->isp_ops->reset_chip(vha);
ha->isp_ops->chip_diag(vha);
goto execute_fw_with_lr;
}
if (IS_ZIO_THRESHOLD_CAPABLE(ha))
qla27xx_set_zio_threshold(vha,
ha->last_zio_threshold);
rval = qla2x00_set_exlogins_buffer(vha);
if (rval != QLA_SUCCESS)
goto failed;
rval = qla2x00_set_exchoffld_buffer(vha);
if (rval != QLA_SUCCESS)
goto failed;
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
if (IS_P3P_TYPE(ha))
qla82xx_check_md_needed(vha);
else
rval = qla2x00_get_fw_version(vha);
if (rval != QLA_SUCCESS)
goto failed;
ha->flags.npiv_supported = 0;
if (IS_QLA2XXX_MIDTYPE(ha) &&
(ha->fw_attributes & BIT_2)) {
ha->flags.npiv_supported = 1;
if ((!ha->max_npiv_vports) ||
((ha->max_npiv_vports + 1) %
MIN_MULTI_ID_FABRIC))
ha->max_npiv_vports =
MIN_MULTI_ID_FABRIC - 1;
}
qla2x00_get_resource_cnts(vha);
qla_init_iocb_limit(vha);
/*
* Allocate the array of outstanding commands
* now that we know the firmware resources.
*/
rval = qla2x00_alloc_outstanding_cmds(ha,
vha->req);
if (rval != QLA_SUCCESS)
goto failed;
if (!fw_major_version && !(IS_P3P_TYPE(ha)))
qla2x00_alloc_offload_mem(vha);
if (ql2xallocfwdump && !(IS_P3P_TYPE(ha)))
qla2x00_alloc_fw_dump(vha);
} else {
goto failed;
}
} else {
ql_log(ql_log_fatal, vha, 0x00cd,
"ISP Firmware failed checksum.\n");
goto failed;
}
/* Enable PUREX PASSTHRU */
if (ql2xrdpenable || ha->flags.scm_supported_f ||
ha->flags.edif_enabled)
qla25xx_set_els_cmds_supported(vha);
} else
goto failed;
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
/* Enable proper parity. */
spin_lock_irqsave(&ha->hardware_lock, flags);
if (IS_QLA2300(ha))
/* SRAM parity */
wrt_reg_word(&reg->hccr, HCCR_ENABLE_PARITY + 0x1);
else
/* SRAM, Instruction RAM and GP RAM parity */
wrt_reg_word(&reg->hccr, HCCR_ENABLE_PARITY + 0x7);
rd_reg_word(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
ha->flags.fac_supported = 1;
else if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
uint32_t size;
rval = qla81xx_fac_get_sector_size(vha, &size);
if (rval == QLA_SUCCESS) {
ha->flags.fac_supported = 1;
ha->fdt_block_size = size << 2;
} else {
ql_log(ql_log_warn, vha, 0x00ce,
"Unsupported FAC firmware (%d.%02d.%02d).\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
if (IS_QLA83XX(ha)) {
ha->flags.fac_supported = 0;
rval = QLA_SUCCESS;
}
}
}
failed:
if (rval) {
ql_log(ql_log_fatal, vha, 0x00cf,
"Setup chip ****FAILED****.\n");
}
return (rval);
}
/**
* qla2x00_init_response_q_entries() - Initializes response queue entries.
* @rsp: response queue
*
* Beginning of request ring has initialization control block already built
* by nvram config routine.
*
* Returns 0 on success.
*/
void
qla2x00_init_response_q_entries(struct rsp_que *rsp)
{
uint16_t cnt;
response_t *pkt;
rsp->ring_ptr = rsp->ring;
rsp->ring_index = 0;
rsp->status_srb = NULL;
pkt = rsp->ring_ptr;
for (cnt = 0; cnt < rsp->length; cnt++) {
pkt->signature = RESPONSE_PROCESSED;
pkt++;
}
}
/**
* qla2x00_update_fw_options() - Read and process firmware options.
* @vha: HA context
*
* Returns 0 on success.
*/
void
qla2x00_update_fw_options(scsi_qla_host_t *vha)
{
uint16_t swing, emphasis, tx_sens, rx_sens;
struct qla_hw_data *ha = vha->hw;
memset(ha->fw_options, 0, sizeof(ha->fw_options));
qla2x00_get_fw_options(vha, ha->fw_options);
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return;
/* Serial Link options. */
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115,
"Serial link options.\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109,
ha->fw_seriallink_options, sizeof(ha->fw_seriallink_options));
ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
if (ha->fw_seriallink_options[3] & BIT_2) {
ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
/* 1G settings */
swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
emphasis = (ha->fw_seriallink_options[2] &
(BIT_4 | BIT_3)) >> 3;
tx_sens = ha->fw_seriallink_options[0] &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
rx_sens = (ha->fw_seriallink_options[0] &
(BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
ha->fw_options[10] = (emphasis << 14) | (swing << 8);
if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
if (rx_sens == 0x0)
rx_sens = 0x3;
ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->fw_options[10] |= BIT_5 |
((rx_sens & (BIT_1 | BIT_0)) << 2) |
(tx_sens & (BIT_1 | BIT_0));
/* 2G settings */
swing = (ha->fw_seriallink_options[2] &
(BIT_7 | BIT_6 | BIT_5)) >> 5;
emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
tx_sens = ha->fw_seriallink_options[1] &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
rx_sens = (ha->fw_seriallink_options[1] &
(BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
ha->fw_options[11] = (emphasis << 14) | (swing << 8);
if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
if (rx_sens == 0x0)
rx_sens = 0x3;
ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->fw_options[11] |= BIT_5 |
((rx_sens & (BIT_1 | BIT_0)) << 2) |
(tx_sens & (BIT_1 | BIT_0));
}
/* FCP2 options. */
/* Return command IOCBs without waiting for an ABTS to complete. */
ha->fw_options[3] |= BIT_13;
/* LED scheme. */
if (ha->flags.enable_led_scheme)
ha->fw_options[2] |= BIT_12;
/* Detect ISP6312. */
if (IS_QLA6312(ha))
ha->fw_options[2] |= BIT_13;
/* Set Retry FLOGI in case of P2P connection */
if (ha->operating_mode == P2P) {
ha->fw_options[2] |= BIT_3;
ql_dbg(ql_dbg_disc, vha, 0x2100,
"(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n",
__func__, ha->fw_options[2]);
}
/* Update firmware options. */
qla2x00_set_fw_options(vha, ha->fw_options);
}
void
qla24xx_update_fw_options(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
if (IS_P3P_TYPE(ha))
return;
/* Hold status IOCBs until ABTS response received. */
if (ql2xfwholdabts)
ha->fw_options[3] |= BIT_12;
/* Set Retry FLOGI in case of P2P connection */
if (ha->operating_mode == P2P) {
ha->fw_options[2] |= BIT_3;
ql_dbg(ql_dbg_disc, vha, 0x2101,
"(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n",
__func__, ha->fw_options[2]);
}
/* Move PUREX, ABTS RX & RIDA to ATIOQ */
if (ql2xmvasynctoatio && !ha->flags.edif_enabled &&
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) {
if (qla_tgt_mode_enabled(vha) ||
qla_dual_mode_enabled(vha))
ha->fw_options[2] |= BIT_11;
else
ha->fw_options[2] &= ~BIT_11;
}
if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
IS_QLA28XX(ha)) {
/*
* Tell FW to track each exchange to prevent
* driver from using stale exchange.
*/
if (qla_tgt_mode_enabled(vha) ||
qla_dual_mode_enabled(vha))
ha->fw_options[2] |= BIT_4;
else
ha->fw_options[2] &= ~(BIT_4);
/* Reserve 1/2 of emergency exchanges for ELS.*/
if (qla2xuseresexchforels)
ha->fw_options[2] |= BIT_8;
else
ha->fw_options[2] &= ~BIT_8;
/*
* N2N: set Secure=1 for PLOGI ACC and
* fw shal not send PRLI after PLOGI Acc
*/
if (ha->flags.edif_enabled &&
DBELL_ACTIVE(vha)) {
ha->fw_options[3] |= BIT_15;
ha->flags.n2n_fw_acc_sec = 1;
} else {
ha->fw_options[3] &= ~BIT_15;
ha->flags.n2n_fw_acc_sec = 0;
}
}
if (ql2xrdpenable || ha->flags.scm_supported_f ||
ha->flags.edif_enabled)
ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;
/* Enable Async 8130/8131 events -- transceiver insertion/removal */
if (IS_BPM_RANGE_CAPABLE(ha))
ha->fw_options[3] |= BIT_10;
ql_dbg(ql_dbg_init, vha, 0x00e8,
"%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n",
__func__, ha->fw_options[1], ha->fw_options[2],
ha->fw_options[3], vha->host->active_mode);
if (ha->fw_options[1] || ha->fw_options[2] || ha->fw_options[3])
qla2x00_set_fw_options(vha, ha->fw_options);
/* Update Serial Link options. */
if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
return;
rval = qla2x00_set_serdes_params(vha,
le16_to_cpu(ha->fw_seriallink_options24[1]),
le16_to_cpu(ha->fw_seriallink_options24[2]),
le16_to_cpu(ha->fw_seriallink_options24[3]));
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x0104,
"Unable to update Serial Link options (%x).\n", rval);
}
}
void
qla2x00_config_rings(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
/* Setup ring parameters in initialization control block. */
ha->init_cb->request_q_outpointer = cpu_to_le16(0);
ha->init_cb->response_q_inpointer = cpu_to_le16(0);
ha->init_cb->request_q_length = cpu_to_le16(req->length);
ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
put_unaligned_le64(req->dma, &ha->init_cb->request_q_address);
put_unaligned_le64(rsp->dma, &ha->init_cb->response_q_address);
wrt_reg_word(ISP_REQ_Q_IN(ha, reg), 0);
wrt_reg_word(ISP_REQ_Q_OUT(ha, reg), 0);
wrt_reg_word(ISP_RSP_Q_IN(ha, reg), 0);
wrt_reg_word(ISP_RSP_Q_OUT(ha, reg), 0);
rd_reg_word(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
}
void
qla24xx_config_rings(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
device_reg_t *reg = ISP_QUE_REG(ha, 0);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
struct qla_msix_entry *msix;
struct init_cb_24xx *icb;
uint16_t rid = 0;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
/* Setup ring parameters in initialization control block. */
icb = (struct init_cb_24xx *)ha->init_cb;
icb->request_q_outpointer = cpu_to_le16(0);
icb->response_q_inpointer = cpu_to_le16(0);
icb->request_q_length = cpu_to_le16(req->length);
icb->response_q_length = cpu_to_le16(rsp->length);
put_unaligned_le64(req->dma, &icb->request_q_address);
put_unaligned_le64(rsp->dma, &icb->response_q_address);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
/* Setup ATIO queue dma pointers for target mode */
icb->atio_q_inpointer = cpu_to_le16(0);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length);
put_unaligned_le64(ha->tgt.atio_dma, &icb->atio_q_address);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
if (IS_SHADOW_REG_CAPABLE(ha))
icb->firmware_options_2 |= cpu_to_le32(BIT_30|BIT_29);
if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
IS_QLA28XX(ha)) {
icb->qos = cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = cpu_to_le16(rid);
if (ha->flags.msix_enabled) {
msix = &ha->msix_entries[1];
ql_dbg(ql_dbg_init, vha, 0x0019,
"Registering vector 0x%x for base que.\n",
msix->entry);
icb->msix = cpu_to_le16(msix->entry);
}
/* Use alternate PCI bus number */
if (MSB(rid))
icb->firmware_options_2 |= cpu_to_le32(BIT_19);
/* Use alternate PCI devfn */
if (LSB(rid))
icb->firmware_options_2 |= cpu_to_le32(BIT_18);
/* Use Disable MSIX Handshake mode for capable adapters */
if ((ha->fw_attributes & BIT_6) && (IS_MSIX_NACK_CAPABLE(ha)) &&
(ha->flags.msix_enabled)) {
icb->firmware_options_2 &= cpu_to_le32(~BIT_22);
ha->flags.disable_msix_handshake = 1;
ql_dbg(ql_dbg_init, vha, 0x00fe,
"MSIX Handshake Disable Mode turned on.\n");
} else {
icb->firmware_options_2 |= cpu_to_le32(BIT_22);
}
icb->firmware_options_2 |= cpu_to_le32(BIT_23);
wrt_reg_dword(&reg->isp25mq.req_q_in, 0);
wrt_reg_dword(&reg->isp25mq.req_q_out, 0);
wrt_reg_dword(&reg->isp25mq.rsp_q_in, 0);
wrt_reg_dword(&reg->isp25mq.rsp_q_out, 0);
} else {
wrt_reg_dword(&reg->isp24.req_q_in, 0);
wrt_reg_dword(&reg->isp24.req_q_out, 0);
wrt_reg_dword(&reg->isp24.rsp_q_in, 0);
wrt_reg_dword(&reg->isp24.rsp_q_out, 0);
}
qlt_24xx_config_rings(vha);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
/* If the user has configured the speed, set it here */
if (ha->set_data_rate) {
ql_dbg(ql_dbg_init, vha, 0x00fd,
"Speed set by user : %s Gbps \n",
qla2x00_get_link_speed_str(ha, ha->set_data_rate));
icb->firmware_options_3 = cpu_to_le32(ha->set_data_rate << 13);
}
/* PCI posting */
rd_reg_word(&ioreg->hccr);
}
/**
* qla2x00_init_rings() - Initializes firmware.
* @vha: HA context
*
* Beginning of request ring has initialization control block already built
* by nvram config routine.
*
* Returns 0 on success.
*/
int
qla2x00_init_rings(scsi_qla_host_t *vha)
{
int rval;
unsigned long flags = 0;
int cnt, que;
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
struct rsp_que *rsp;
struct mid_init_cb_24xx *mid_init_cb =
(struct mid_init_cb_24xx *) ha->init_cb;
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Clear outstanding commands array. */
for (que = 0; que < ha->max_req_queues; que++) {
req = ha->req_q_map[que];
if (!req || !test_bit(que, ha->req_qid_map))
continue;
req->out_ptr = (uint16_t *)(req->ring + req->length);
*req->out_ptr = 0;
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++)
req->outstanding_cmds[cnt] = NULL;
req->current_outstanding_cmd = 1;
/* Initialize firmware. */
req->ring_ptr = req->ring;
req->ring_index = 0;
req->cnt = req->length;
}
for (que = 0; que < ha->max_rsp_queues; que++) {
rsp = ha->rsp_q_map[que];
if (!rsp || !test_bit(que, ha->rsp_qid_map))
continue;
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
*rsp->in_ptr = 0;
/* Initialize response queue entries */
if (IS_QLAFX00(ha))
qlafx00_init_response_q_entries(rsp);
else
qla2x00_init_response_q_entries(rsp);
}
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
ha->tgt.atio_ring_ptr = ha->tgt.atio_ring;
ha->tgt.atio_ring_index = 0;
/* Initialize ATIO queue entries */
qlt_init_atio_q_entries(vha);
ha->isp_ops->config_rings(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (IS_QLAFX00(ha)) {
rval = qlafx00_init_firmware(vha, ha->init_cb_size);
goto next_check;
}
/* Update any ISP specific firmware options before initialization. */
ha->isp_ops->update_fw_options(vha);
ql_dbg(ql_dbg_init, vha, 0x00d1,
"Issue init firmware FW opt 1-3= %08x %08x %08x.\n",
le32_to_cpu(mid_init_cb->init_cb.firmware_options_1),
le32_to_cpu(mid_init_cb->init_cb.firmware_options_2),
le32_to_cpu(mid_init_cb->init_cb.firmware_options_3));
if (ha->flags.npiv_supported) {
if (ha->operating_mode == LOOP && !IS_CNA_CAPABLE(ha))
ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
}
if (IS_FWI2_CAPABLE(ha)) {
mid_init_cb->options = cpu_to_le16(BIT_1);
mid_init_cb->init_cb.execution_throttle =
cpu_to_le16(ha->cur_fw_xcb_count);
ha->flags.dport_enabled =
(le32_to_cpu(mid_init_cb->init_cb.firmware_options_1) &
BIT_7) != 0;
ql_dbg(ql_dbg_init, vha, 0x0191, "DPORT Support: %s.\n",
(ha->flags.dport_enabled) ? "enabled" : "disabled");
/* FA-WWPN Status */
ha->flags.fawwpn_enabled =
(le32_to_cpu(mid_init_cb->init_cb.firmware_options_1) &
BIT_6) != 0;
ql_dbg(ql_dbg_init, vha, 0x00bc, "FA-WWPN Support: %s.\n",
(ha->flags.fawwpn_enabled) ? "enabled" : "disabled");
/* Init_cb will be reused for other command(s). Save a backup copy of port_name */
memcpy(ha->port_name, ha->init_cb->port_name, WWN_SIZE);
}
/* ELS pass through payload is limit by frame size. */
if (ha->flags.edif_enabled)
mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD);
rval = qla2x00_init_firmware(vha, ha->init_cb_size);
next_check:
if (rval) {
ql_log(ql_log_fatal, vha, 0x00d2,
"Init Firmware **** FAILED ****.\n");
} else {
ql_dbg(ql_dbg_init, vha, 0x00d3,
"Init Firmware -- success.\n");
QLA_FW_STARTED(ha);
vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0;
}
return (rval);
}
/**
* qla2x00_fw_ready() - Waits for firmware ready.
* @vha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_fw_ready(scsi_qla_host_t *vha)
{
int rval;
unsigned long wtime, mtime, cs84xx_time;
uint16_t min_wait; /* Minimum wait time if loop is down */
uint16_t wait_time; /* Wait time if loop is coming ready */
uint16_t state[6];
struct qla_hw_data *ha = vha->hw;
if (IS_QLAFX00(vha->hw))
return qlafx00_fw_ready(vha);
/* Time to wait for loop down */
if (IS_P3P_TYPE(ha))
min_wait = 30;
else
min_wait = 20;
/*
* Firmware should take at most one RATOV to login, plus 5 seconds for
* our own processing.
*/
if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
wait_time = min_wait;
}
/* Min wait time if loop down */
mtime = jiffies + (min_wait * HZ);
/* wait time before firmware ready */
wtime = jiffies + (wait_time * HZ);
/* Wait for ISP to finish LIP */
if (!vha->flags.init_done)
ql_log(ql_log_info, vha, 0x801e,
"Waiting for LIP to complete.\n");
do {
memset(state, -1, sizeof(state));
rval = qla2x00_get_firmware_state(vha, state);
if (rval == QLA_SUCCESS) {
if (state[0] < FSTATE_LOSS_OF_SYNC) {
vha->device_flags &= ~DFLG_NO_CABLE;
}
if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
ql_dbg(ql_dbg_taskm, vha, 0x801f,
"fw_state=%x 84xx=%x.\n", state[0],
state[2]);
if ((state[2] & FSTATE_LOGGED_IN) &&
(state[2] & FSTATE_WAITING_FOR_VERIFY)) {
ql_dbg(ql_dbg_taskm, vha, 0x8028,
"Sending verify iocb.\n");
cs84xx_time = jiffies;
rval = qla84xx_init_chip(vha);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn,
vha, 0x8007,
"Init chip failed.\n");
break;
}
/* Add time taken to initialize. */
cs84xx_time = jiffies - cs84xx_time;
wtime += cs84xx_time;
mtime += cs84xx_time;
ql_dbg(ql_dbg_taskm, vha, 0x8008,
"Increasing wait time by %ld. "
"New time %ld.\n", cs84xx_time,
wtime);
}
} else if (state[0] == FSTATE_READY) {
ql_dbg(ql_dbg_taskm, vha, 0x8037,
"F/W Ready - OK.\n");
qla2x00_get_retry_cnt(vha, &ha->retry_count,
&ha->login_timeout, &ha->r_a_tov);
rval = QLA_SUCCESS;
break;
}
rval = QLA_FUNCTION_FAILED;
if (atomic_read(&vha->loop_down_timer) &&
state[0] != FSTATE_READY) {
/* Loop down. Timeout on min_wait for states
* other than Wait for Login.
*/
if (time_after_eq(jiffies, mtime)) {
ql_log(ql_log_info, vha, 0x8038,
"Cable is unplugged...\n");
vha->device_flags |= DFLG_NO_CABLE;
break;
}
}
} else {
/* Mailbox cmd failed. Timeout on min_wait. */
if (time_after_eq(jiffies, mtime) ||
ha->flags.isp82xx_fw_hung)
break;
}
if (time_after_eq(jiffies, wtime))
break;
/* Delay for a while */
msleep(500);
} while (1);
ql_dbg(ql_dbg_taskm, vha, 0x803a,
"fw_state=%x (%x, %x, %x, %x %x) curr time=%lx.\n", state[0],
state[1], state[2], state[3], state[4], state[5], jiffies);
if (rval && !(vha->device_flags & DFLG_NO_CABLE)) {
ql_log(ql_log_warn, vha, 0x803b,
"Firmware ready **** FAILED ****.\n");
}
return (rval);
}
/*
* qla2x00_configure_hba
* Setup adapter context.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
static int
qla2x00_configure_hba(scsi_qla_host_t *vha)
{
int rval;
uint16_t loop_id;
uint16_t topo;
uint16_t sw_cap;
uint8_t al_pa;
uint8_t area;
uint8_t domain;
char connect_type[22];
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
port_id_t id;
unsigned long flags;
/* Get host addresses. */
rval = qla2x00_get_adapter_id(vha,
&loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
if (rval != QLA_SUCCESS) {
if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
IS_CNA_CAPABLE(ha) ||
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
ql_dbg(ql_dbg_disc, vha, 0x2008,
"Loop is in a transition state.\n");
} else {
ql_log(ql_log_warn, vha, 0x2009,
"Unable to get host loop ID.\n");
if (IS_FWI2_CAPABLE(ha) && (vha == base_vha) &&
(rval == QLA_COMMAND_ERROR && loop_id == 0x1b)) {
ql_log(ql_log_warn, vha, 0x1151,
"Doing link init.\n");
if (qla24xx_link_initialize(vha) == QLA_SUCCESS)
return rval;
}
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
}
return (rval);
}
if (topo == 4) {
ql_log(ql_log_info, vha, 0x200a,
"Cannot get topology - retrying.\n");
return (QLA_FUNCTION_FAILED);
}
vha->loop_id = loop_id;
/* initialize */
ha->min_external_loopid = SNS_FIRST_LOOP_ID;
ha->operating_mode = LOOP;
switch (topo) {
case 0:
ql_dbg(ql_dbg_disc, vha, 0x200b, "HBA in NL topology.\n");
ha->switch_cap = 0;
ha->current_topology = ISP_CFG_NL;
strcpy(connect_type, "(Loop)");
break;
case 1:
ql_dbg(ql_dbg_disc, vha, 0x200c, "HBA in FL topology.\n");
ha->switch_cap = sw_cap;
ha->current_topology = ISP_CFG_FL;
strcpy(connect_type, "(FL_Port)");
break;
case 2:
ql_dbg(ql_dbg_disc, vha, 0x200d, "HBA in N P2P topology.\n");
ha->switch_cap = 0;
ha->operating_mode = P2P;
ha->current_topology = ISP_CFG_N;
strcpy(connect_type, "(N_Port-to-N_Port)");
break;
case 3:
ql_dbg(ql_dbg_disc, vha, 0x200e, "HBA in F P2P topology.\n");
ha->switch_cap = sw_cap;
ha->operating_mode = P2P;
ha->current_topology = ISP_CFG_F;
strcpy(connect_type, "(F_Port)");
break;
default:
ql_dbg(ql_dbg_disc, vha, 0x200f,
"HBA in unknown topology %x, using NL.\n", topo);
ha->switch_cap = 0;
ha->current_topology = ISP_CFG_NL;
strcpy(connect_type, "(Loop)");
break;
}
/* Save Host port and loop ID. */
/* byte order - Big Endian */
id.b.domain = domain;
id.b.area = area;
id.b.al_pa = al_pa;
id.b.rsvd_1 = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
if (vha->hw->flags.edif_enabled) {
if (topo != 2)
qla_update_host_map(vha, id);
} else if (!(topo == 2 && ha->flags.n2n_bigger))
qla_update_host_map(vha, id);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
if (!vha->flags.init_done)
ql_log(ql_log_info, vha, 0x2010,
"Topology - %s, Host Loop address 0x%x.\n",
connect_type, vha->loop_id);
return(rval);
}
inline void
qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
const char *def)
{
char *st, *en;
uint16_t index;
uint64_t zero[2] = { 0 };
struct qla_hw_data *ha = vha->hw;
int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha);
if (len > sizeof(zero))
len = sizeof(zero);
if (memcmp(model, &zero, len) != 0) {
memcpy(ha->model_number, model, len);
st = en = ha->model_number;
en += len - 1;
while (en > st) {
if (*en != 0x20 && *en != 0x00)
break;
*en-- = '\0';
}
index = (ha->pdev->subsystem_device & 0xff);
if (use_tbl &&
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
index < QLA_MODEL_NAMES)
strscpy(ha->model_desc,
qla2x00_model_name[index * 2 + 1],
sizeof(ha->model_desc));
} else {
index = (ha->pdev->subsystem_device & 0xff);
if (use_tbl &&
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
index < QLA_MODEL_NAMES) {
strscpy(ha->model_number,
qla2x00_model_name[index * 2],
sizeof(ha->model_number));
strscpy(ha->model_desc,
qla2x00_model_name[index * 2 + 1],
sizeof(ha->model_desc));
} else {
strscpy(ha->model_number, def,
sizeof(ha->model_number));
}
}
if (IS_FWI2_CAPABLE(ha))
qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc,
sizeof(ha->model_desc));
}
/* On sparc systems, obtain port and node WWN from firmware
* properties.
*/
static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv)
{
#ifdef CONFIG_SPARC
struct qla_hw_data *ha = vha->hw;
struct pci_dev *pdev = ha->pdev;
struct device_node *dp = pci_device_to_OF_node(pdev);
const u8 *val;
int len;
val = of_get_property(dp, "port-wwn", &len);
if (val && len >= WWN_SIZE)
memcpy(nv->port_name, val, WWN_SIZE);
val = of_get_property(dp, "node-wwn", &len);
if (val && len >= WWN_SIZE)
memcpy(nv->node_name, val, WWN_SIZE);
#endif
}
/*
* NVRAM configuration for ISP 2xxx
*
* Input:
* ha = adapter block pointer.
*
* Output:
* initialization control block in response_ring
* host adapters parameters in host adapter block
*
* Returns:
* 0 = success.
*/
int
qla2x00_nvram_config(scsi_qla_host_t *vha)
{
int rval;
uint8_t chksum = 0;
uint16_t cnt;
uint8_t *dptr1, *dptr2;
struct qla_hw_data *ha = vha->hw;
init_cb_t *icb = ha->init_cb;
nvram_t *nv = ha->nvram;
uint8_t *ptr = ha->nvram;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
rval = QLA_SUCCESS;
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(*nv);
ha->nvram_base = 0;
if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
if ((rd_reg_word(&reg->ctrl_status) >> 14) == 1)
ha->nvram_base = 0x80;
/* Get NVRAM data and calculate checksum. */
ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
chksum += *ptr++;
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f,
"Contents of NVRAM.\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110,
nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
nv->nvram_version < 1) {
/* Reset NVRAM data. */
ql_log(ql_log_warn, vha, 0x0064,
"Inconsistent NVRAM detected: checksum=%#x id=%.4s version=%#x.\n",
chksum, nv->id, nv->nvram_version);
ql_log(ql_log_warn, vha, 0x0065,
"Falling back to "
"functioning (yet invalid -- WWPN) defaults.\n");
/*
* Set default initialization control block.
*/
memset(nv, 0, ha->nvram_size);
nv->parameter_block_version = ICB_VERSION;
if (IS_QLA23XX(ha)) {
nv->firmware_options[0] = BIT_2 | BIT_1;
nv->firmware_options[1] = BIT_7 | BIT_5;
nv->add_firmware_options[0] = BIT_5;
nv->add_firmware_options[1] = BIT_5 | BIT_4;
nv->frame_payload_size = cpu_to_le16(2048);
nv->special_options[1] = BIT_7;
} else if (IS_QLA2200(ha)) {
nv->firmware_options[0] = BIT_2 | BIT_1;
nv->firmware_options[1] = BIT_7 | BIT_5;
nv->add_firmware_options[0] = BIT_5;
nv->add_firmware_options[1] = BIT_5 | BIT_4;
nv->frame_payload_size = cpu_to_le16(1024);
} else if (IS_QLA2100(ha)) {
nv->firmware_options[0] = BIT_3 | BIT_1;
nv->firmware_options[1] = BIT_5;
nv->frame_payload_size = cpu_to_le16(1024);
}
nv->max_iocb_allocation = cpu_to_le16(256);
nv->execution_throttle = cpu_to_le16(16);
nv->retry_count = 8;
nv->retry_delay = 1;
nv->port_name[0] = 33;
nv->port_name[3] = 224;
nv->port_name[4] = 139;
qla2xxx_nvram_wwn_from_ofw(vha, nv);
nv->login_timeout = 4;
/*
* Set default host adapter parameters
*/
nv->host_p[1] = BIT_2;
nv->reset_delay = 5;
nv->port_down_retry_count = 8;
nv->max_luns_per_target = cpu_to_le16(8);
nv->link_down_timeout = 60;
rval = 1;
}
/* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size);
/*
* Setup driver NVRAM options.
*/
nv->firmware_options[0] |= (BIT_6 | BIT_1);
nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
nv->firmware_options[1] |= (BIT_5 | BIT_0);
nv->firmware_options[1] &= ~BIT_4;
if (IS_QLA23XX(ha)) {
nv->firmware_options[0] |= BIT_2;
nv->firmware_options[0] &= ~BIT_3;
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
nv->special_options[0] &= ~BIT_6;
nv->add_firmware_options[1] |= BIT_5 | BIT_4;
if (IS_QLA2300(ha)) {
if (ha->fb_rev == FPM_2310) {
strcpy(ha->model_number, "QLA2310");
} else {
strcpy(ha->model_number, "QLA2300");
}
} else {
qla2x00_set_model_info(vha, nv->model_number,
sizeof(nv->model_number), "QLA23xx");
}
} else if (IS_QLA2200(ha)) {
nv->firmware_options[0] |= BIT_2;
/*
* 'Point-to-point preferred, else loop' is not a safe
* connection mode setting.
*/
if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
(BIT_5 | BIT_4)) {
/* Force 'loop preferred, else point-to-point'. */
nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
nv->add_firmware_options[0] |= BIT_5;
}
strcpy(ha->model_number, "QLA22xx");
} else /*if (IS_QLA2100(ha))*/ {
strcpy(ha->model_number, "QLA2100");
}
/*
* Copy over NVRAM RISC parameter block to initialization control block.
*/
dptr1 = (uint8_t *)icb;
dptr2 = (uint8_t *)&nv->parameter_block_version;
cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
while (cnt--)
*dptr1++ = *dptr2++;
/* Copy 2nd half. */
dptr1 = (uint8_t *)icb->add_firmware_options;
cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
while (cnt--)
*dptr1++ = *dptr2++;
ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size);
/* Use alternate WWN? */
if (nv->host_p[1] & BIT_7) {
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
/* Prepare nodename */
if ((icb->firmware_options[1] & BIT_6) == 0) {
/*
* Firmware will apply the following mask if the nodename was
* not provided.
*/
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
icb->node_name[0] &= 0xF0;
}
/*
* Set host adapter parameters.
*/
/*
* BIT_7 in the host-parameters section allows for modification to
* internal driver logging.
*/
if (nv->host_p[0] & BIT_7)
ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
/* Always load RISC code on non ISP2[12]00 chips. */
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
ha->flags.disable_serdes = 0;
ha->operating_mode =
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
memcpy(ha->fw_seriallink_options, nv->seriallink_options,
sizeof(ha->fw_seriallink_options));
/* save HBA serial number */
ha->serial0 = icb->port_name[5];
ha->serial1 = icb->port_name[6];
ha->serial2 = icb->port_name[7];
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
icb->execution_throttle = cpu_to_le16(0xFFFF);
ha->retry_count = nv->retry_count;
/* Set minimum login_timeout to 4 seconds. */
if (nv->login_timeout != ql2xlogintimeout)
nv->login_timeout = ql2xlogintimeout;
if (nv->login_timeout < 4)
nv->login_timeout = 4;
ha->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
ha->loop_reset_delay = nv->reset_delay;
/* Link Down Timeout = 0:
*
* When Port Down timer expires we will start returning
* I/O's to OS with "DID_NO_CONNECT".
*
* Link Down Timeout != 0:
*
* The driver waits for the link to come up after link down
* before returning I/Os to OS with "DID_NO_CONNECT".
*/
if (nv->link_down_timeout == 0) {
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
} else {
ha->link_down_timeout = nv->link_down_timeout;
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - ha->link_down_timeout);
}
/*
* Need enough time to try and get the port back.
*/
ha->port_down_retry_count = nv->port_down_retry_count;
if (qlport_down_retry)
ha->port_down_retry_count = qlport_down_retry;
/* Set login_retry_count */
ha->login_retry_count = nv->retry_count;
if (ha->port_down_retry_count == nv->port_down_retry_count &&
ha->port_down_retry_count > 3)
ha->login_retry_count = ha->port_down_retry_count;
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
ha->login_retry_count = ha->port_down_retry_count;
if (ql2xloginretrycount)
ha->login_retry_count = ql2xloginretrycount;
icb->lun_enables = cpu_to_le16(0);
icb->command_resource_count = 0;
icb->immediate_notify_resource_count = 0;
icb->timeout = cpu_to_le16(0);
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
/* Enable RIO */
icb->firmware_options[0] &= ~BIT_3;
icb->add_firmware_options[0] &=
~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
icb->add_firmware_options[0] |= BIT_2;
icb->response_accumulation_timer = 3;
icb->interrupt_delay_timer = 5;
vha->flags.process_response_queue = 1;
} else {
/* Enable ZIO. */
if (!vha->flags.init_done) {
ha->zio_mode = icb->add_firmware_options[0] &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = icb->interrupt_delay_timer ?
icb->interrupt_delay_timer : 2;
}
icb->add_firmware_options[0] &=
~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
vha->flags.process_response_queue = 0;
if (ha->zio_mode != QLA_ZIO_DISABLED) {
ha->zio_mode = QLA_ZIO_MODE_6;
ql_log(ql_log_info, vha, 0x0068,
"ZIO mode %d enabled; timer delay (%d us).\n",
ha->zio_mode, ha->zio_timer * 100);
icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
vha->flags.process_response_queue = 1;
}
}
if (rval) {
ql_log(ql_log_warn, vha, 0x0069,
"NVRAM configuration failed.\n");
}
return (rval);
}
void qla2x00_set_fcport_state(fc_port_t *fcport, int state)
{
int old_state;
old_state = atomic_read(&fcport->state);
atomic_set(&fcport->state, state);
/* Don't print state transitions during initial allocation of fcport */
if (old_state && old_state != state) {
ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
"FCPort %8phC state transitioned from %s to %s - portid=%02x%02x%02x.\n",
fcport->port_name, port_state_str[old_state],
port_state_str[state], fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
}
}
/**
* qla2x00_alloc_fcport() - Allocate a generic fcport.
* @vha: HA context
* @flags: allocation flags
*
* Returns a pointer to the allocated fcport, or NULL, if none available.
*/
fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
{
fc_port_t *fcport;
fcport = kzalloc(sizeof(fc_port_t), flags);
if (!fcport)
return NULL;
fcport->ct_desc.ct_sns = dma_alloc_coherent(&vha->hw->pdev->dev,
sizeof(struct ct_sns_pkt), &fcport->ct_desc.ct_sns_dma,
flags);
if (!fcport->ct_desc.ct_sns) {
ql_log(ql_log_warn, vha, 0xd049,
"Failed to allocate ct_sns request.\n");
kfree(fcport);
return NULL;
}
/* Setup fcport template structure. */
fcport->vha = vha;
fcport->port_type = FCT_UNKNOWN;
fcport->loop_id = FC_NO_LOOP_ID;
qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED);
fcport->supported_classes = FC_COS_UNSPECIFIED;
fcport->fp_speed = PORT_SPEED_UNKNOWN;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->disc_state = DSC_DELETED;
fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
fcport->deleted = QLA_SESS_DELETED;
fcport->login_retry = vha->hw->login_retry_count;
fcport->chip_reset = vha->hw->base_qpair->chip_reset;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fcport->logout_on_delete = 1;
fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
fcport->tgt_short_link_down_cnt = 0;
fcport->dev_loss_tmo = 0;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (!fcport->ct_desc.ct_sns) {
ql_log(ql_log_warn, vha, 0xd049,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"Failed to allocate ct_sns request.\n");
kfree(fcport);
return NULL;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn);
scsi: qla2xxx: Initialize free_work before flushing it Target creation triggers a new BUG_ON introduced in in commit 4d43d395fed1 ("workqueue: Try to catch flush_work() without INIT_WORK()."). The BUG_ON reveals an attempt to flush free_work in qla24xx_do_nack_work before it's initialized in qlt_unreg_sess: WARNING: CPU: 7 PID: 211 at kernel/workqueue.c:3031 __flush_work.isra.38+0x40/0x2e0 CPU: 7 PID: 211 Comm: kworker/7:1 Kdump: loaded Tainted: G E 5.3.0-rc7-vanilla+ #2 Workqueue: qla2xxx_wq qla2x00_iocb_work_fn [qla2xxx] NIP: c000000000159620 LR: c0080000009d91b0 CTR: c0000000001598c0 REGS: c000000005f3f730 TRAP: 0700 Tainted: G E (5.3.0-rc7-vanilla+) MSR: 800000000282b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 24002222 XER: 00000000 CFAR: c0000000001598d0 IRQMASK: 0 GPR00: c0080000009d91b0 c000000005f3f9c0 c000000001670a00 c0000003f8655ca8 GPR04: c0000003f8655c00 000000000000ffff 0000000000000011 ffffffffffffffff GPR08: c008000000949228 0000000000000000 0000000000000001 c0080000009e7780 GPR12: 0000000000002200 c00000003fff6200 c000000000161bc8 0000000000000004 GPR16: c0000003f9d68280 0000000002000000 0000000000000005 0000000000000003 GPR20: 0000000000000002 000000000000ffff 0000000000000000 fffffffffffffef7 GPR24: c000000004f73848 c000000004f73838 c000000004f73f28 c000000005f3fb60 GPR28: c000000004f73e48 c000000004f73c80 c000000004f73818 c0000003f9d68280 NIP [c000000000159620] __flush_work.isra.38+0x40/0x2e0 LR [c0080000009d91b0] qla24xx_do_nack_work+0x88/0x180 [qla2xxx] Call Trace: [c000000005f3f9c0] [c000000000159644] __flush_work.isra.38+0x64/0x2e0 (unreliable) [c000000005f3fa50] [c0080000009d91a0] qla24xx_do_nack_work+0x78/0x180 [qla2xxx] [c000000005f3fae0] [c0080000009496ec] qla2x00_do_work+0x604/0xb90 [qla2xxx] [c000000005f3fc40] [c008000000949cd8] qla2x00_iocb_work_fn+0x60/0xe0 [qla2xxx] [c000000005f3fc80] [c000000000157bb8] process_one_work+0x2c8/0x5b0 [c000000005f3fd10] [c000000000157f28] worker_thread+0x88/0x660 [c000000005f3fdb0] [c000000000161d64] kthread+0x1a4/0x1b0 [c000000005f3fe20] [c00000000000b960] ret_from_kernel_thread+0x5c/0x7c Instruction dump: 3d22001d 892966b1 7d908026 91810008 f821ff71 69290001 0b090000 2e290000 40920200 e9230018 7d2a0074 794ad182 <0b0a0000> 2fa90000 419e01e8 7c0802a6 ---[ end trace 5ccf335d4f90fcb8 ]--- Fixes: 1021f0bc2f3d6 ("scsi: qla2xxx: allow session delete to finish before create.") Cc: Quinn Tran <qutran@marvell.com> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191125165702.1013-4-r.bolshakov@yadro.com Acked-by: Himanshu Madhani <hmadhani@marvell.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-11-25 16:56:52 +00:00
INIT_WORK(&fcport->free_work, qlt_free_session_done);
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
INIT_LIST_HEAD(&fcport->gnl_entry);
INIT_LIST_HEAD(&fcport->list);
INIT_LIST_HEAD(&fcport->tmf_pending);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
INIT_LIST_HEAD(&fcport->sess_cmd_list);
spin_lock_init(&fcport->sess_cmd_lock);
scsi: qla2xxx: edif: Add key update Some FC adapters from Marvell offer the ability to encrypt data in flight (EDIF). This feature requires an application to act as an authenticator. As part of the authentication process, the authentication application will generate a SADB entry (Security Association/SA, key, SPI value, etc). This SADB is then passed to driver to be programmed into hardware. There will be a pair of SADB's (Tx and Rx) for each connection. After some period, the application can choose to change the key. At that time, a new set of SADB pair is given to driver. The old set of SADB will be deleted. Add a new bsg call (QL_VND_SC_SA_UPDATE) to allow application to allow adding or deleting SADB entries. Driver will not keep the key in memory. It will pass it to HW. It is assumed that application will assign a unique SPI value to this SADB (SA + key). Driver + hardware will assign a handle to track this unique SPI/SADB. Link: https://lore.kernel.org/r/20210624052606.21613-6-njavali@marvell.com Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Co-developed-by: Larry Wisneski <Larry.Wisneski@marvell.com> Signed-off-by: Larry Wisneski <Larry.Wisneski@marvell.com> Co-developed-by: Duane Grigsby <duane.grigsby@marvell.com> Signed-off-by: Duane Grigsby <duane.grigsby@marvell.com> Co-developed-by: Rick Hicksted Jr <rhicksted@marvell.com> Signed-off-by: Rick Hicksted Jr <rhicksted@marvell.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-06-24 05:26:00 +00:00
spin_lock_init(&fcport->edif.sa_list_lock);
INIT_LIST_HEAD(&fcport->edif.tx_sa_list);
INIT_LIST_HEAD(&fcport->edif.rx_sa_list);
spin_lock_init(&fcport->edif.indx_list_lock);
INIT_LIST_HEAD(&fcport->edif.edif_indx_list);
return fcport;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
void
qla2x00_free_fcport(fc_port_t *fcport)
{
if (fcport->ct_desc.ct_sns) {
dma_free_coherent(&fcport->vha->hw->pdev->dev,
sizeof(struct ct_sns_pkt), fcport->ct_desc.ct_sns,
fcport->ct_desc.ct_sns_dma);
fcport->ct_desc.ct_sns = NULL;
}
qla_edif_flush_sa_ctl_lists(fcport);
list_del(&fcport->list);
qla2x00_clear_loop_id(fcport);
qla_edif_list_del(fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
kfree(fcport);
}
static void qla_get_login_template(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
int rval;
u32 *bp, sz;
__be32 *q;
memset(ha->init_cb, 0, ha->init_cb_size);
sz = min_t(int, sizeof(struct fc_els_csp), ha->init_cb_size);
rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma,
ha->init_cb, sz);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_init, vha, 0x00d1,
"PLOGI ELS param read fail.\n");
return;
}
q = (__be32 *)&ha->plogi_els_payld.fl_csp;
bp = (uint32_t *)ha->init_cb;
cpu_to_be32_array(q, bp, sz / 4);
ha->flags.plogi_template_valid = 1;
}
/*
* qla2x00_configure_loop
* Updates Fibre Channel Device Database with what is actually on loop.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success.
* 1 = error.
* 2 = database was full and device was not configured.
*/
static int
qla2x00_configure_loop(scsi_qla_host_t *vha)
{
int rval;
unsigned long flags, save_flags;
struct qla_hw_data *ha = vha->hw;
rval = QLA_SUCCESS;
/* Get Initiator ID */
if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
rval = qla2x00_configure_hba(vha);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0x2013,
"Unable to configure HBA.\n");
return (rval);
}
}
save_flags = flags = vha->dpc_flags;
ql_dbg(ql_dbg_disc, vha, 0x2014,
"Configure loop -- dpc flags = 0x%lx.\n", flags);
/*
* If we have both an RSCN and PORT UPDATE pending then handle them
* both at the same time.
*/
clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
clear_bit(RSCN_UPDATE, &vha->dpc_flags);
qla2x00_get_data_rate(vha);
qla_get_login_template(vha);
/* Determine what we need to do */
if ((ha->current_topology == ISP_CFG_FL ||
ha->current_topology == ISP_CFG_F) &&
(test_bit(LOCAL_LOOP_UPDATE, &flags))) {
set_bit(RSCN_UPDATE, &flags);
clear_bit(LOCAL_LOOP_UPDATE, &flags);
} else if (ha->current_topology == ISP_CFG_NL ||
ha->current_topology == ISP_CFG_N) {
clear_bit(RSCN_UPDATE, &flags);
set_bit(LOCAL_LOOP_UPDATE, &flags);
} else if (!vha->flags.online ||
(test_bit(ABORT_ISP_ACTIVE, &flags))) {
set_bit(RSCN_UPDATE, &flags);
set_bit(LOCAL_LOOP_UPDATE, &flags);
}
if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
ql_dbg(ql_dbg_disc, vha, 0x2015,
"Loop resync needed, failing.\n");
rval = QLA_FUNCTION_FAILED;
} else
rval = qla2x00_configure_local_loop(vha);
}
if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
if (LOOP_TRANSITION(vha)) {
ql_dbg(ql_dbg_disc, vha, 0x2099,
"Needs RSCN update and loop transition.\n");
rval = QLA_FUNCTION_FAILED;
}
else
rval = qla2x00_configure_fabric(vha);
}
if (rval == QLA_SUCCESS) {
if (atomic_read(&vha->loop_down_timer) ||
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
rval = QLA_FUNCTION_FAILED;
} else {
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
ha->flags.fw_init_done = 1;
qla2xxx: Check for online flag instead of active reset when transmitting responses Driver has following initialization sequence for Target mode 1. Driver initialization starts 2. ISP Abort is scheduled when the target is enabled. qla2xxx [0000:04:00.0]-4807:25: ISP abort scheduled qla2xxx [0000:04:00.0]-00af:25: Performing ISP error recovery - ha=ffff880caa9e0000. 3. DPC thread starts the ISP Abort 4. While DPC is resetting the chip and initializing the firmware, we get async events from the firmware about P2P mode, LOOP UP and PORT UPDATE. 5. PRLI from a initiator is delivered to us followed by a PLOGI and then a SCSI command which creates a session. 6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it gets dropped as can be seen with messages RESET-XFR because ISP Abort is still active qla2xxx [0000:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1. 7. If the SCSI command is a READ, we issue RESPONSE and they get dropped as well because Abort is still active. qla2xxx [0000:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1 8. Now eventually, ISP Abort finishes clearing the DPC flags. qla2xxx [0000:04:00.0]-8822:25: qla2x00_abort_isp succeeded. qla2xxx [0000:04:00.0]-4808:25: ISP abort end. 9. Since we dropped SCSI commands silently (without any responses sent to the initiator) initiator waits for a SCSI timeout (which is 60 seconds in our case), Sends an ABTS which fails since there no se_cmd found for the tag that ABTS is referencing as the commands were cleaned up in Step 6 and 7. 10. Initiator send an IO after the ABTS which succeed fine. To fix the above case, the following changes have been made: - To prevent target from dropping commands silently, use the online flag instead to check for an active chip reset. Once the port is online during a chip reset phase, we are good to process the commands. - Clean up qla2x00_restart_isp to not set the online flag and process ATIO as it is unnecessary. During a chip reset, interrupts are enabled only after setting the online flag to 1, so ATIO's won't be missed and hence no need to process ATIO's after setting the online flag. Signed-off-by: Dilip Kumar Uppugandla <dilip@purestorage.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-12-17 19:57:11 +00:00
/*
* use link up to wake up app to get ready for
* authentication.
*/
if (ha->flags.edif_enabled && DBELL_INACTIVE(vha))
qla2x00_post_aen_work(vha, FCH_EVT_LINKUP,
ha->link_data_rate);
qla2xxx: Check for online flag instead of active reset when transmitting responses Driver has following initialization sequence for Target mode 1. Driver initialization starts 2. ISP Abort is scheduled when the target is enabled. qla2xxx [0000:04:00.0]-4807:25: ISP abort scheduled qla2xxx [0000:04:00.0]-00af:25: Performing ISP error recovery - ha=ffff880caa9e0000. 3. DPC thread starts the ISP Abort 4. While DPC is resetting the chip and initializing the firmware, we get async events from the firmware about P2P mode, LOOP UP and PORT UPDATE. 5. PRLI from a initiator is delivered to us followed by a PLOGI and then a SCSI command which creates a session. 6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it gets dropped as can be seen with messages RESET-XFR because ISP Abort is still active qla2xxx [0000:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1. 7. If the SCSI command is a READ, we issue RESPONSE and they get dropped as well because Abort is still active. qla2xxx [0000:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1 8. Now eventually, ISP Abort finishes clearing the DPC flags. qla2xxx [0000:04:00.0]-8822:25: qla2x00_abort_isp succeeded. qla2xxx [0000:04:00.0]-4808:25: ISP abort end. 9. Since we dropped SCSI commands silently (without any responses sent to the initiator) initiator waits for a SCSI timeout (which is 60 seconds in our case), Sends an ABTS which fails since there no se_cmd found for the tag that ABTS is referencing as the commands were cleaned up in Step 6 and 7. 10. Initiator send an IO after the ABTS which succeed fine. To fix the above case, the following changes have been made: - To prevent target from dropping commands silently, use the online flag instead to check for an active chip reset. Once the port is online during a chip reset phase, we are good to process the commands. - Clean up qla2x00_restart_isp to not set the online flag and process ATIO as it is unnecessary. During a chip reset, interrupts are enabled only after setting the online flag to 1, so ATIO's won't be missed and hence no need to process ATIO's after setting the online flag. Signed-off-by: Dilip Kumar Uppugandla <dilip@purestorage.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-12-17 19:57:11 +00:00
/*
* Process any ATIO queue entries that came in
* while we weren't online.
*/
if (qla_tgt_mode_enabled(vha) ||
qla_dual_mode_enabled(vha)) {
spin_lock_irqsave(&ha->tgt.atio_lock, flags);
qlt_24xx_process_atio_queue(vha, 0);
spin_unlock_irqrestore(&ha->tgt.atio_lock,
flags);
qla2xxx: Check for online flag instead of active reset when transmitting responses Driver has following initialization sequence for Target mode 1. Driver initialization starts 2. ISP Abort is scheduled when the target is enabled. qla2xxx [0000:04:00.0]-4807:25: ISP abort scheduled qla2xxx [0000:04:00.0]-00af:25: Performing ISP error recovery - ha=ffff880caa9e0000. 3. DPC thread starts the ISP Abort 4. While DPC is resetting the chip and initializing the firmware, we get async events from the firmware about P2P mode, LOOP UP and PORT UPDATE. 5. PRLI from a initiator is delivered to us followed by a PLOGI and then a SCSI command which creates a session. 6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it gets dropped as can be seen with messages RESET-XFR because ISP Abort is still active qla2xxx [0000:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1. 7. If the SCSI command is a READ, we issue RESPONSE and they get dropped as well because Abort is still active. qla2xxx [0000:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1 8. Now eventually, ISP Abort finishes clearing the DPC flags. qla2xxx [0000:04:00.0]-8822:25: qla2x00_abort_isp succeeded. qla2xxx [0000:04:00.0]-4808:25: ISP abort end. 9. Since we dropped SCSI commands silently (without any responses sent to the initiator) initiator waits for a SCSI timeout (which is 60 seconds in our case), Sends an ABTS which fails since there no se_cmd found for the tag that ABTS is referencing as the commands were cleaned up in Step 6 and 7. 10. Initiator send an IO after the ABTS which succeed fine. To fix the above case, the following changes have been made: - To prevent target from dropping commands silently, use the online flag instead to check for an active chip reset. Once the port is online during a chip reset phase, we are good to process the commands. - Clean up qla2x00_restart_isp to not set the online flag and process ATIO as it is unnecessary. During a chip reset, interrupts are enabled only after setting the online flag to 1, so ATIO's won't be missed and hence no need to process ATIO's after setting the online flag. Signed-off-by: Dilip Kumar Uppugandla <dilip@purestorage.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-12-17 19:57:11 +00:00
}
}
}
if (rval) {
ql_dbg(ql_dbg_disc, vha, 0x206a,
"%s *** FAILED ***.\n", __func__);
} else {
ql_dbg(ql_dbg_disc, vha, 0x206b,
"%s: exiting normally. local port wwpn %8phN id %06x)\n",
__func__, vha->port_name, vha->d_id.b24);
}
/* Restore state if a resync event occurred during processing */
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
if (test_bit(RSCN_UPDATE, &save_flags)) {
set_bit(RSCN_UPDATE, &vha->dpc_flags);
}
}
return (rval);
}
static int qla2x00_configure_n2n_loop(scsi_qla_host_t *vha)
{
unsigned long flags;
fc_port_t *fcport;
ql_dbg(ql_dbg_disc, vha, 0x206a, "%s %d.\n", __func__, __LINE__);
if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags))
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->n2n_flag) {
qla24xx_fcport_handle_login(vha, fcport);
return QLA_SUCCESS;
}
}
spin_lock_irqsave(&vha->work_lock, flags);
vha->scan.scan_retry++;
spin_unlock_irqrestore(&vha->work_lock, flags);
if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
return QLA_FUNCTION_FAILED;
}
static void
qla_reinitialize_link(scsi_qla_host_t *vha)
{
int rval;
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
rval = qla2x00_full_login_lip(vha);
if (rval == QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0xd050, "Link reinitialized\n");
} else {
ql_dbg(ql_dbg_disc, vha, 0xd051,
"Link reinitialization failed (%d)\n", rval);
}
}
/*
* qla2x00_configure_local_loop
* Updates Fibre Channel Device Database with local loop devices.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success.
*/
static int
qla2x00_configure_local_loop(scsi_qla_host_t *vha)
{
int rval, rval2;
int found;
fc_port_t *fcport, *new_fcport;
uint16_t index;
uint16_t entries;
struct gid_list_info *gid;
uint16_t loop_id;
uint8_t domain, area, al_pa;
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
/* Inititae N2N login. */
if (N2N_TOPO(ha))
return qla2x00_configure_n2n_loop(vha);
new_fcport = NULL;
entries = MAX_FIBRE_DEVICES_LOOP;
/* Get list of logged in devices. */
memset(ha->gid_list, 0, qla2x00_gid_list_size(ha));
rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
&entries);
if (rval != QLA_SUCCESS)
scsi: qla2xxx: Fix a NULL pointer dereference in an error path This patch fixes the following Coverity complaint: FORWARD_NULL qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } Fixes: 3dae220595ba ("scsi: qla2xxx: Use common routine to free fcport struct") Cc: Himanshu Madhani <hmadhani@marvell.com> Cc: Quinn Tran <qutran@marvell.com> Cc: Martin Wilck <mwilck@suse.com> Cc: Daniel Wagner <dwagner@suse.de> Cc: Roman Bolshakov <r.bolshakov@yadro.com> Link: https://lore.kernel.org/r/20200118042056.32232-1-bvanassche@acm.org Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-01-18 04:20:56 +00:00
goto err;
ql_dbg(ql_dbg_disc, vha, 0x2011,
"Entries in ID list (%d).\n", entries);
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
ha->gid_list, entries * sizeof(*ha->gid_list));
if (entries == 0) {
spin_lock_irqsave(&vha->work_lock, flags);
vha->scan.scan_retry++;
spin_unlock_irqrestore(&vha->work_lock, flags);
if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
u8 loop_map_entries = 0;
int rc;
rc = qla2x00_get_fcal_position_map(vha, NULL,
&loop_map_entries);
if (rc == QLA_SUCCESS && loop_map_entries > 1) {
/*
* There are devices that are still not logged
* in. Reinitialize to give them a chance.
*/
qla_reinitialize_link(vha);
return QLA_FUNCTION_FAILED;
}
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
} else {
vha->scan.scan_retry = 0;
}
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->scan_state = QLA_FCPORT_SCAN;
}
/* Allocate temporary fcport for any new fcports discovered. */
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (new_fcport == NULL) {
ql_log(ql_log_warn, vha, 0x2012,
"Memory allocation failed for fcport.\n");
rval = QLA_MEMORY_ALLOC_FAILED;
scsi: qla2xxx: Fix a NULL pointer dereference in an error path This patch fixes the following Coverity complaint: FORWARD_NULL qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } Fixes: 3dae220595ba ("scsi: qla2xxx: Use common routine to free fcport struct") Cc: Himanshu Madhani <hmadhani@marvell.com> Cc: Quinn Tran <qutran@marvell.com> Cc: Martin Wilck <mwilck@suse.com> Cc: Daniel Wagner <dwagner@suse.de> Cc: Roman Bolshakov <r.bolshakov@yadro.com> Link: https://lore.kernel.org/r/20200118042056.32232-1-bvanassche@acm.org Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-01-18 04:20:56 +00:00
goto err;
}
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
/* Add devices to port list. */
gid = ha->gid_list;
for (index = 0; index < entries; index++) {
domain = gid->domain;
area = gid->area;
al_pa = gid->al_pa;
if (IS_QLA2100(ha) || IS_QLA2200(ha))
loop_id = gid->loop_id_2100;
else
loop_id = le16_to_cpu(gid->loop_id);
gid = (void *)gid + ha->gid_list_info_size;
/* Bypass reserved domain fields. */
if ((domain & 0xf0) == 0xf0)
continue;
/* Bypass if not same domain and area of adapter. */
if (area && domain && ((area != vha->d_id.b.area) ||
(domain != vha->d_id.b.domain)) &&
(ha->current_topology == ISP_CFG_NL))
continue;
/* Bypass invalid local loop ID. */
if (loop_id > LAST_LOCAL_LOOP_ID)
continue;
memset(new_fcport->port_name, 0, WWN_SIZE);
/* Fill in member data. */
new_fcport->d_id.b.domain = domain;
new_fcport->d_id.b.area = area;
new_fcport->d_id.b.al_pa = al_pa;
new_fcport->loop_id = loop_id;
new_fcport->scan_state = QLA_FCPORT_FOUND;
rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
if (rval2 != QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0x2097,
"Failed to retrieve fcport information "
"-- get_port_database=%x, loop_id=0x%04x.\n",
rval2, new_fcport->loop_id);
/* Skip retry if N2N */
if (ha->current_topology != ISP_CFG_N) {
ql_dbg(ql_dbg_disc, vha, 0x2105,
"Scheduling resync.\n");
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
continue;
}
}
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
/* Check for matching device in port list. */
found = 0;
fcport = NULL;
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
fcport->flags &= ~FCF_FABRIC_DEVICE;
fcport->loop_id = new_fcport->loop_id;
fcport->port_type = new_fcport->port_type;
fcport->d_id.b24 = new_fcport->d_id.b24;
memcpy(fcport->node_name, new_fcport->node_name,
WWN_SIZE);
fcport->scan_state = QLA_FCPORT_FOUND;
if (fcport->login_retry == 0) {
fcport->login_retry = vha->hw->login_retry_count;
ql_dbg(ql_dbg_disc, vha, 0x2135,
"Port login retry %8phN, lid 0x%04x retry cnt=%d.\n",
fcport->port_name, fcport->loop_id,
fcport->login_retry);
}
found++;
break;
}
if (!found) {
/* New device, add to fcports list. */
list_add_tail(&new_fcport->list, &vha->vp_fcports);
/* Allocate a new replacement fcport. */
fcport = new_fcport;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (new_fcport == NULL) {
ql_log(ql_log_warn, vha, 0xd031,
"Failed to allocate memory for fcport.\n");
rval = QLA_MEMORY_ALLOC_FAILED;
scsi: qla2xxx: Fix a NULL pointer dereference in an error path This patch fixes the following Coverity complaint: FORWARD_NULL qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } Fixes: 3dae220595ba ("scsi: qla2xxx: Use common routine to free fcport struct") Cc: Himanshu Madhani <hmadhani@marvell.com> Cc: Quinn Tran <qutran@marvell.com> Cc: Martin Wilck <mwilck@suse.com> Cc: Daniel Wagner <dwagner@suse.de> Cc: Roman Bolshakov <r.bolshakov@yadro.com> Link: https://lore.kernel.org/r/20200118042056.32232-1-bvanassche@acm.org Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-01-18 04:20:56 +00:00
goto err;
}
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
}
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
/* Base iIDMA settings on HBA port speed. */
fcport->fp_speed = ha->link_data_rate;
}
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
break;
if (fcport->scan_state == QLA_FCPORT_SCAN) {
if ((qla_dual_mode_enabled(vha) ||
qla_ini_mode_enabled(vha)) &&
atomic_read(&fcport->state) == FCS_ONLINE) {
qla2x00_mark_device_lost(vha, fcport,
ql2xplogiabsentdevice);
if (fcport->loop_id != FC_NO_LOOP_ID &&
(fcport->flags & FCF_FCP2_DEVICE) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
ql_dbg(ql_dbg_disc, vha, 0x20f0,
"%s %d %8phC post del sess\n",
__func__, __LINE__,
fcport->port_name);
qlt_schedule_sess_for_deletion(fcport);
continue;
}
}
}
if (fcport->scan_state == QLA_FCPORT_FOUND)
qla24xx_fcport_handle_login(vha, fcport);
}
qla2x00_free_fcport(new_fcport);
scsi: qla2xxx: Fix a NULL pointer dereference in an error path This patch fixes the following Coverity complaint: FORWARD_NULL qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } Fixes: 3dae220595ba ("scsi: qla2xxx: Use common routine to free fcport struct") Cc: Himanshu Madhani <hmadhani@marvell.com> Cc: Quinn Tran <qutran@marvell.com> Cc: Martin Wilck <mwilck@suse.com> Cc: Daniel Wagner <dwagner@suse.de> Cc: Roman Bolshakov <r.bolshakov@yadro.com> Link: https://lore.kernel.org/r/20200118042056.32232-1-bvanassche@acm.org Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-01-18 04:20:56 +00:00
return rval;
scsi: qla2xxx: Fix a NULL pointer dereference in an error path This patch fixes the following Coverity complaint: FORWARD_NULL qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } qla_init.c: 5275 in qla2x00_configure_local_loop() 5269 5270 if (fcport->scan_state == QLA_FCPORT_FOUND) 5271 qla24xx_fcport_handle_login(vha, fcport); 5272 } 5273 5274 cleanup_allocation: >>> CID 353340: (FORWARD_NULL) >>> Passing null pointer "new_fcport" to "qla2x00_free_fcport", which dereferences it. 5275 qla2x00_free_fcport(new_fcport); 5276 5277 if (rval != QLA_SUCCESS) { 5278 ql_dbg(ql_dbg_disc, vha, 0x2098, 5279 "Configure local loop error exit: rval=%x.\n", rval); 5280 } Fixes: 3dae220595ba ("scsi: qla2xxx: Use common routine to free fcport struct") Cc: Himanshu Madhani <hmadhani@marvell.com> Cc: Quinn Tran <qutran@marvell.com> Cc: Martin Wilck <mwilck@suse.com> Cc: Daniel Wagner <dwagner@suse.de> Cc: Roman Bolshakov <r.bolshakov@yadro.com> Link: https://lore.kernel.org/r/20200118042056.32232-1-bvanassche@acm.org Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-01-18 04:20:56 +00:00
err:
ql_dbg(ql_dbg_disc, vha, 0x2098,
"Configure local loop error exit: rval=%x.\n", rval);
return rval;
}
static void
qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
int rval;
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct qla_hw_data *ha = vha->hw;
if (!IS_IIDMA_CAPABLE(ha))
return;
if (atomic_read(&fcport->state) != FCS_ONLINE)
return;
if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
fcport->fp_speed > ha->link_data_rate ||
!ha->flags.gpsc_supported)
return;
rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
mb);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0x2004,
"Unable to adjust iIDMA %8phN -- %04x %x %04x %04x.\n",
fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]);
} else {
ql_dbg(ql_dbg_disc, vha, 0x2005,
"iIDMA adjusted to %s GB/s (%X) on %8phN.\n",
qla2x00_get_link_speed_str(ha, fcport->fp_speed),
fcport->fp_speed, fcport->port_name);
}
}
void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
qla2x00_iidma_fcport(vha, fcport);
qla24xx_update_fcport_fcp_prio(vha, fcport);
}
int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_IIDMA);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
return qla2x00_post_work(vha, e);
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
/* qla2x00_reg_remote_port is reserved for Initiator Mode only.*/
static void
qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
{
struct fc_rport_identifiers rport_ids;
struct fc_rport *rport;
unsigned long flags;
if (atomic_read(&fcport->state) == FCS_ONLINE)
return;
rport_ids.node_name = wwn_to_u64(fcport->node_name);
rport_ids.port_name = wwn_to_u64(fcport->port_name);
rport_ids.port_id = fcport->d_id.b.domain << 16 |
fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
if (!rport) {
ql_log(ql_log_warn, vha, 0x2006,
"Unable to allocate fc remote port.\n");
return;
}
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
spin_lock_irqsave(fcport->vha->host->host_lock, flags);
[SCSI] update fc_transport for removal of block/unblock functions We recently went back to implement a board reset. When we perform the reset, we wanted to tear down the internal data structures and rebuild them. Unfortunately, when it came to the rport structure, things were odd. If we deleted them, the scsi targets and sdevs would be torn down. Not a good thing for a temporary reset. We could block the rports, but we either maintain the internal structures to keep the rport reference (perhaps even replicating what's in the transport), or we have to fatten the fc transport with new search routines to find the rport (and deal with a case of a dangling rport that the driver forgets). It dawned on me that we had actually reached this state incorrectly. When the fc transport first started, we did the block/unblock first, then added the rport interface. The purpose of block/unblock is to hide the temporary disappearance of the rport (e.g. being deleted, then readded). Why are we making the driver do the block/unblock ? We should be making the transport have only an rport add/delete, and the let the transport handle the block/unblock. So... This patch removes the existing fc_remote_port_block/unblock functions. It moves the block/unblock functionality into the fc_remote_port_add/delete functions. Updates for the lpfc driver are included. Qlogic driver updates are also enclosed, thanks to the contributions of Andrew Vasquez. [Note: the qla2xxx changes are relative to the scsi-misc-2.6 tree as of this morning - which does not include the recent patches sent by Andrew]. The zfcp driver does not use the block/unblock functions. One last comment: The resulting behavior feels very clean. The LLDD is concerned only with add/delete, which corresponds to the physical disappearance. However, the fact that the scsi target and sdevs are not immediately torn down after the LLDD calls delete causes an interesting scenario... the midlayer can call the xxx_slave_alloc and xxx_queuecommand functions with a sdev that is at the location the rport used to be. The driver must validate the device exists when it first enters these functions. In thinking about it, this has always been the case for the LLDD and these routines. The existing drivers already check for existence. However, this highlights that simple validation via data structure dereferencing needs to be watched. To deal with this, a new transport function, fc_remote_port_chkready() was created that LLDDs should call when they first enter these two routines. It validates the rport state, and returns a scsi result which could be returned. In addition to solving the above, it also creates consistent behavior from the LLDD's when the block and deletes are occuring. Rejections fixed up and Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-10-18 16:03:35 +00:00
*((fc_port_t **)rport->dd_data) = fcport;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
fcport->dev_loss_tmo = rport->dev_loss_tmo;
rport->supported_classes = fcport->supported_classes;
rport_ids.roles = FC_PORT_ROLE_UNKNOWN;
if (fcport->port_type == FCT_INITIATOR)
rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
if (fcport->port_type == FCT_TARGET)
rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET;
if (fcport->port_type & FCT_NVME_INITIATOR)
rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR;
if (fcport->port_type & FCT_NVME_TARGET)
rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET;
if (fcport->port_type & FCT_NVME_DISCOVERY)
rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fc_remote_port_rolechg(rport, rport_ids.roles);
ql_dbg(ql_dbg_disc, vha, 0x20ee,
"%s: %8phN. rport %ld:0:%d (%p) is %s mode\n",
__func__, fcport->port_name, vha->host_no,
rport->scsi_target_id, rport,
(fcport->port_type == FCT_TARGET) ? "tgt" :
((fcport->port_type & FCT_NVME) ? "nvme" : "ini"));
}
/*
* qla2x00_update_fcport
* Updates device on list.
*
* Input:
* ha = adapter block pointer.
* fcport = port structure pointer.
*
* Return:
* 0 - Success
* BIT_0 - error
*
* Context:
* Kernel context.
*/
void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (IS_SW_RESV_ADDR(fcport->d_id))
return;
ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n",
__func__, fcport->port_name);
qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT);
fcport->login_retry = vha->hw->login_retry_count;
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
fcport->deleted = 0;
if (vha->hw->current_topology == ISP_CFG_NL)
fcport->logout_on_delete = 0;
else
fcport->logout_on_delete = 1;
fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
if (fcport->tgt_link_down_time < fcport->dev_loss_tmo) {
fcport->tgt_short_link_down_cnt++;
fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
}
switch (vha->hw->current_topology) {
case ISP_CFG_N:
case ISP_CFG_NL:
fcport->keep_nport_handle = 1;
break;
default:
break;
}
qla2x00_iidma_fcport(vha, fcport);
qla2x00_dfs_create_rport(vha, fcport);
qla24xx_update_fcport_fcp_prio(vha, fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
switch (vha->host->active_mode) {
case MODE_INITIATOR:
qla2x00_reg_remote_port(vha, fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
break;
case MODE_TARGET:
if (!vha->vha_tgt.qla_tgt->tgt_stop &&
!vha->vha_tgt.qla_tgt->tgt_stopped)
qlt_fc_port_added(vha, fcport);
break;
case MODE_DUAL:
qla2x00_reg_remote_port(vha, fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (!vha->vha_tgt.qla_tgt->tgt_stop &&
!vha->vha_tgt.qla_tgt->tgt_stopped)
qlt_fc_port_added(vha, fcport);
break;
default:
break;
}
if (NVME_TARGET(vha->hw, fcport))
qla_nvme_register_remote(vha, fcport);
qla2x00_set_fcport_state(fcport, FCS_ONLINE);
if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) {
if (fcport->id_changed) {
fcport->id_changed = 0;
ql_dbg(ql_dbg_disc, vha, 0x20d7,
"%s %d %8phC post gfpnid fcp_cnt %d\n",
__func__, __LINE__, fcport->port_name,
vha->fcport_count);
qla24xx_post_gfpnid_work(vha, fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20d7,
"%s %d %8phC post gpsc fcp_cnt %d\n",
__func__, __LINE__, fcport->port_name,
vha->fcport_count);
qla24xx_post_gpsc_work(vha, fcport);
}
}
qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_COMPLETE);
}
void qla_register_fcport_fn(struct work_struct *work)
{
fc_port_t *fcport = container_of(work, struct fc_port, reg_work);
u32 rscn_gen = fcport->rscn_gen;
u16 data[2];
if (IS_SW_RESV_ADDR(fcport->d_id))
return;
qla2x00_update_fcport(fcport->vha, fcport);
ql_dbg(ql_dbg_disc, fcport->vha, 0x911e,
"%s rscn gen %d/%d next DS %d\n", __func__,
rscn_gen, fcport->rscn_gen, fcport->next_disc_state);
if (rscn_gen != fcport->rscn_gen) {
/* RSCN(s) came in while registration */
switch (fcport->next_disc_state) {
case DSC_DELETE_PEND:
qlt_schedule_sess_for_deletion(fcport);
break;
case DSC_ADISC:
data[0] = data[1] = 0;
qla2x00_post_async_adisc_work(fcport->vha, fcport,
data);
break;
default:
break;
}
}
}
/*
* qla2x00_configure_fabric
* Setup SNS devices with loop ID's.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success.
* BIT_0 = error
*/
static int
qla2x00_configure_fabric(scsi_qla_host_t *vha)
{
int rval;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fc_port_t *fcport;
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint16_t loop_id;
struct qla_hw_data *ha = vha->hw;
int discovery_gen;
/* If FL port exists, then SNS is present */
if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0x20a0,
"MBX_GET_PORT_NAME failed, No FL Port.\n");
vha->device_flags &= ~SWITCH_FOUND;
return (QLA_SUCCESS);
}
vha->device_flags |= SWITCH_FOUND;
rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_port_name, 0);
if (rval != QLA_SUCCESS)
ql_dbg(ql_dbg_disc, vha, 0x20ff,
"Failed to get Fabric Port Name\n");
if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) {
rval = qla2x00_send_change_request(vha, 0x3, 0);
if (rval != QLA_SUCCESS)
ql_log(ql_log_warn, vha, 0x121,
"Failed to enable receiving of RSCN requests: 0x%x.\n",
rval);
}
do {
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla2x00_mgmt_svr_login(vha);
/* Ensure we are logged into the SNS. */
loop_id = NPH_SNS_LID(ha);
rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
0xfc, mb, BIT_1|BIT_0);
if (rval != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) {
ql_dbg(ql_dbg_disc, vha, 0x20a1,
"Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x (%x).\n",
loop_id, mb[0], mb[1], mb[2], mb[6], mb[7], rval);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
return rval;
}
/* FDMI support. */
if (ql2xfdmienable &&
test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags))
qla2x00_fdmi_register(vha);
if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
if (qla2x00_rft_id(vha)) {
/* EMPTY */
ql_dbg(ql_dbg_disc, vha, 0x20a2,
"Register FC-4 TYPE failed.\n");
if (test_bit(LOOP_RESYNC_NEEDED,
&vha->dpc_flags))
break;
}
if (qla2x00_rff_id(vha, FC4_TYPE_FCP_SCSI)) {
/* EMPTY */
ql_dbg(ql_dbg_disc, vha, 0x209a,
"Register FC-4 Features failed.\n");
if (test_bit(LOOP_RESYNC_NEEDED,
&vha->dpc_flags))
break;
}
if (vha->flags.nvme_enabled) {
if (qla2x00_rff_id(vha, FC_TYPE_NVME)) {
ql_dbg(ql_dbg_disc, vha, 0x2049,
"Register NVME FC Type Features failed.\n");
}
}
if (qla2x00_rnn_id(vha)) {
/* EMPTY */
ql_dbg(ql_dbg_disc, vha, 0x2104,
"Register Node Name failed.\n");
if (test_bit(LOOP_RESYNC_NEEDED,
&vha->dpc_flags))
break;
} else if (qla2x00_rsnn_nn(vha)) {
/* EMPTY */
ql_dbg(ql_dbg_disc, vha, 0x209b,
"Register Symbolic Node Name failed.\n");
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
break;
}
}
/* Mark the time right before querying FW for connected ports.
* This process is long, asynchronous and by the time it's done,
* collected information might not be accurate anymore. E.g.
* disconnected port might have re-connected and a brand new
* session has been created. In this case session's generation
* will be newer than discovery_gen. */
qlt_do_generation_tick(vha, &discovery_gen);
if (USE_ASYNC_SCAN(ha)) {
rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI,
NULL);
if (rval)
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
} else {
list_for_each_entry(fcport, &vha->vp_fcports, list)
fcport->scan_state = QLA_FCPORT_SCAN;
rval = qla2x00_find_all_fabric_devs(vha);
}
if (rval != QLA_SUCCESS)
break;
} while (0);
if (!vha->nvme_local_port && vha->flags.nvme_enabled)
qla_nvme_register_hba(vha);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (rval)
ql_dbg(ql_dbg_disc, vha, 0x2068,
"Configure fabric error exit rval=%d.\n", rval);
return (rval);
}
/*
* qla2x00_find_all_fabric_devs
*
* Input:
* ha = adapter block pointer.
* dev = database device entry pointer.
*
* Returns:
* 0 = success.
*
* Context:
* Kernel context.
*/
static int
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
{
int rval;
uint16_t loop_id;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
fc_port_t *fcport, *new_fcport;
int found;
sw_info_t *swl;
int swl_idx;
int first_dev, last_dev;
port_id_t wrap = {}, nxt_d_id;
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
unsigned long flags;
rval = QLA_SUCCESS;
/* Try GID_PT to get device list, else GAN. */
if (!ha->swl)
ha->swl = kcalloc(ha->max_fibre_devices, sizeof(sw_info_t),
GFP_KERNEL);
swl = ha->swl;
if (!swl) {
/*EMPTY*/
ql_dbg(ql_dbg_disc, vha, 0x209c,
"GID_PT allocations failed, fallback on GA_NXT.\n");
} else {
memset(swl, 0, ha->max_fibre_devices * sizeof(sw_info_t));
if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
swl = NULL;
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
return rval;
} else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
swl = NULL;
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
return rval;
} else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
swl = NULL;
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
return rval;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
} else if (qla2x00_gfpn_id(vha, swl) != QLA_SUCCESS) {
swl = NULL;
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
return rval;
}
/* If other queries succeeded probe for FC-4 type */
if (swl) {
qla2x00_gff_id(vha, swl);
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
return rval;
}
}
swl_idx = 0;
/* Allocate temporary fcport for any new fcports discovered. */
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (new_fcport == NULL) {
ql_log(ql_log_warn, vha, 0x209d,
"Failed to allocate memory for fcport.\n");
return (QLA_MEMORY_ALLOC_FAILED);
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
/* Set start port ID scan at adapter ID. */
first_dev = 1;
last_dev = 0;
/* Starting free loop ID. */
loop_id = ha->min_external_loopid;
for (; loop_id <= ha->max_loop_id; loop_id++) {
if (qla2x00_is_reserved_id(vha, loop_id))
continue;
if (ha->current_topology == ISP_CFG_FL &&
(atomic_read(&vha->loop_down_timer) ||
LOOP_TRANSITION(vha))) {
atomic_set(&vha->loop_down_timer, 0);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
break;
}
if (swl != NULL) {
if (last_dev) {
wrap.b24 = new_fcport->d_id.b24;
} else {
new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
memcpy(new_fcport->node_name,
swl[swl_idx].node_name, WWN_SIZE);
memcpy(new_fcport->port_name,
swl[swl_idx].port_name, WWN_SIZE);
memcpy(new_fcport->fabric_port_name,
swl[swl_idx].fabric_port_name, WWN_SIZE);
new_fcport->fp_speed = swl[swl_idx].fp_speed;
new_fcport->fc4_type = swl[swl_idx].fc4_type;
new_fcport->nvme_flag = 0;
if (vha->flags.nvme_enabled &&
swl[swl_idx].fc4_type & FS_FC4TYPE_NVME) {
ql_log(ql_log_info, vha, 0x2131,
"FOUND: NVME port %8phC as FC Type 28h\n",
new_fcport->port_name);
}
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
}
swl_idx++;
}
} else {
/* Send GA_NXT to the switch */
rval = qla2x00_ga_nxt(vha, new_fcport);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x209e,
"SNS scan failed -- assuming "
"zero-entry result.\n");
rval = QLA_SUCCESS;
break;
}
}
/* If wrap on switch device list, exit. */
if (first_dev) {
wrap.b24 = new_fcport->d_id.b24;
first_dev = 0;
} else if (new_fcport->d_id.b24 == wrap.b24) {
ql_dbg(ql_dbg_disc, vha, 0x209f,
"Device wrap (%02x%02x%02x).\n",
new_fcport->d_id.b.domain,
new_fcport->d_id.b.area,
new_fcport->d_id.b.al_pa);
break;
}
/* Bypass if same physical adapter. */
if (new_fcport->d_id.b24 == base_vha->d_id.b24)
continue;
/* Bypass virtual ports of the same host. */
if (qla2x00_is_a_vp_did(vha, new_fcport->d_id.b24))
continue;
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(vha->d_id.b24 & 0xffff00)) && ha->current_topology ==
ISP_CFG_FL)
continue;
/* Bypass reserved domain fields. */
if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
continue;
/* Bypass ports whose FCP-4 type is not FCP_SCSI */
if (ql2xgffidenable &&
(!(new_fcport->fc4_type & FS_FC4TYPE_FCP) &&
new_fcport->fc4_type != 0))
continue;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
/* Locate matching device in database. */
found = 0;
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
fcport->scan_state = QLA_FCPORT_FOUND;
found++;
/* Update port state. */
memcpy(fcport->fabric_port_name,
new_fcport->fabric_port_name, WWN_SIZE);
fcport->fp_speed = new_fcport->fp_speed;
/*
qla2xxx: kill sessions/log out initiator on RSCN and port down events To fix some issues talking to ESX, this patch modifies the qla2xxx driver so that it never logs into remote ports. This has the side effect of getting rid of the "rports" entirely, which means we never log out of initiators and never tear down sessions when an initiator goes away. This is mostly OK, except that we can run into trouble if we have initiator A assigned FC address X:Y:Z by the fabric talking to us, and then initiator A goes away. Some time (could be a long time) later, initiator B comes along and also gets FC address X:Y:Z (which is available again, because initiator A is gone). If initiator B starts talking to us, then we'll still have the session for initiator A, and since we look up incoming IO based on the FC address X:Y:Z, initiator B will end up using ACLs for initiator A. Fix this by: 1. Handling RSCN events somewhat differently; instead of completely skipping the processing of fcports, we look through the list, and if an fcport disappears, we tell the target code the tear down the session and tell the HBA FW to release the N_Port handle. 2. Handling "port down" events by flushing all of our sessions. The firmware was already releasing the N_Port handle but we want the target code to drop all the sessions too. Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-07-14 20:00:42 +00:00
* If address the same and state FCS_ONLINE
* (or in target mode), nothing changed.
*/
if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
qla2xxx: kill sessions/log out initiator on RSCN and port down events To fix some issues talking to ESX, this patch modifies the qla2xxx driver so that it never logs into remote ports. This has the side effect of getting rid of the "rports" entirely, which means we never log out of initiators and never tear down sessions when an initiator goes away. This is mostly OK, except that we can run into trouble if we have initiator A assigned FC address X:Y:Z by the fabric talking to us, and then initiator A goes away. Some time (could be a long time) later, initiator B comes along and also gets FC address X:Y:Z (which is available again, because initiator A is gone). If initiator B starts talking to us, then we'll still have the session for initiator A, and since we look up incoming IO based on the FC address X:Y:Z, initiator B will end up using ACLs for initiator A. Fix this by: 1. Handling RSCN events somewhat differently; instead of completely skipping the processing of fcports, we look through the list, and if an fcport disappears, we tell the target code the tear down the session and tell the HBA FW to release the N_Port handle. 2. Handling "port down" events by flushing all of our sessions. The firmware was already releasing the N_Port handle but we want the target code to drop all the sessions too. Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-07-14 20:00:42 +00:00
(atomic_read(&fcport->state) == FCS_ONLINE ||
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
(vha->host->active_mode == MODE_TARGET))) {
break;
}
if (fcport->login_retry == 0)
fcport->login_retry =
vha->hw->login_retry_count;
/*
* If device was not a fabric device before.
*/
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
fcport->d_id.b24 = new_fcport->d_id.b24;
qla2x00_clear_loop_id(fcport);
fcport->flags |= (FCF_FABRIC_DEVICE |
FCF_LOGIN_NEEDED);
break;
}
/*
* Port ID changed or device was marked to be updated;
* Log it out if still logged in and mark it for
* relogin later.
*/
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (qla_tgt_mode_enabled(base_vha)) {
qla2xxx: kill sessions/log out initiator on RSCN and port down events To fix some issues talking to ESX, this patch modifies the qla2xxx driver so that it never logs into remote ports. This has the side effect of getting rid of the "rports" entirely, which means we never log out of initiators and never tear down sessions when an initiator goes away. This is mostly OK, except that we can run into trouble if we have initiator A assigned FC address X:Y:Z by the fabric talking to us, and then initiator A goes away. Some time (could be a long time) later, initiator B comes along and also gets FC address X:Y:Z (which is available again, because initiator A is gone). If initiator B starts talking to us, then we'll still have the session for initiator A, and since we look up incoming IO based on the FC address X:Y:Z, initiator B will end up using ACLs for initiator A. Fix this by: 1. Handling RSCN events somewhat differently; instead of completely skipping the processing of fcports, we look through the list, and if an fcport disappears, we tell the target code the tear down the session and tell the HBA FW to release the N_Port handle. 2. Handling "port down" events by flushing all of our sessions. The firmware was already releasing the N_Port handle but we want the target code to drop all the sessions too. Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-07-14 20:00:42 +00:00
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf080,
"port changed FC ID, %8phC"
" old %x:%x:%x (loop_id 0x%04x)-> new %x:%x:%x\n",
fcport->port_name,
fcport->d_id.b.domain,
fcport->d_id.b.area,
fcport->d_id.b.al_pa,
fcport->loop_id,
new_fcport->d_id.b.domain,
new_fcport->d_id.b.area,
new_fcport->d_id.b.al_pa);
fcport->d_id.b24 = new_fcport->d_id.b24;
break;
}
fcport->d_id.b24 = new_fcport->d_id.b24;
fcport->flags |= FCF_LOGIN_NEEDED;
break;
}
if (found && NVME_TARGET(vha->hw, fcport)) {
if (fcport->disc_state == DSC_DELETE_PEND) {
qla2x00_set_fcport_disc_state(fcport, DSC_GNL);
vha->fcport_count--;
fcport->login_succ = 0;
}
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (found) {
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
continue;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
}
/* If device was not in our fcports list, then add it. */
qla2xxx: kill sessions/log out initiator on RSCN and port down events To fix some issues talking to ESX, this patch modifies the qla2xxx driver so that it never logs into remote ports. This has the side effect of getting rid of the "rports" entirely, which means we never log out of initiators and never tear down sessions when an initiator goes away. This is mostly OK, except that we can run into trouble if we have initiator A assigned FC address X:Y:Z by the fabric talking to us, and then initiator A goes away. Some time (could be a long time) later, initiator B comes along and also gets FC address X:Y:Z (which is available again, because initiator A is gone). If initiator B starts talking to us, then we'll still have the session for initiator A, and since we look up incoming IO based on the FC address X:Y:Z, initiator B will end up using ACLs for initiator A. Fix this by: 1. Handling RSCN events somewhat differently; instead of completely skipping the processing of fcports, we look through the list, and if an fcport disappears, we tell the target code the tear down the session and tell the HBA FW to release the N_Port handle. 2. Handling "port down" events by flushing all of our sessions. The firmware was already releasing the N_Port handle but we want the target code to drop all the sessions too. Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2015-07-14 20:00:42 +00:00
new_fcport->scan_state = QLA_FCPORT_FOUND;
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
list_add_tail(&new_fcport->list, &vha->vp_fcports);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
/* Allocate a new replacement fcport. */
nxt_d_id.b24 = new_fcport->d_id.b24;
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (new_fcport == NULL) {
ql_log(ql_log_warn, vha, 0xd032,
"Memory allocation failed for fcport.\n");
return (QLA_MEMORY_ALLOC_FAILED);
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
new_fcport->d_id.b24 = nxt_d_id.b24;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla2x00_free_fcport(new_fcport);
/*
* Logout all previous fabric dev marked lost, except FCP2 devices.
*/
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
break;
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
continue;
if (fcport->scan_state == QLA_FCPORT_SCAN) {
if ((qla_dual_mode_enabled(vha) ||
qla_ini_mode_enabled(vha)) &&
atomic_read(&fcport->state) == FCS_ONLINE) {
qla2x00_mark_device_lost(vha, fcport,
ql2xplogiabsentdevice);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (fcport->loop_id != FC_NO_LOOP_ID &&
(fcport->flags & FCF_FCP2_DEVICE) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
ql_dbg(ql_dbg_disc, vha, 0x20f0,
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
"%s %d %8phC post del sess\n",
__func__, __LINE__,
fcport->port_name);
qlt_schedule_sess_for_deletion(fcport);
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
continue;
}
}
}
if (fcport->scan_state == QLA_FCPORT_FOUND &&
(fcport->flags & FCF_LOGIN_NEEDED) != 0)
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
qla24xx_fcport_handle_login(vha, fcport);
}
return (rval);
}
/* FW does not set aside Loop id for MGMT Server/FFFFFAh */
int
qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *vha)
{
int loop_id = FC_NO_LOOP_ID;
int lid = NPH_MGMT_SERVER - vha->vp_idx;
unsigned long flags;
struct qla_hw_data *ha = vha->hw;
if (vha->vp_idx == 0) {
set_bit(NPH_MGMT_SERVER, ha->loop_id_map);
return NPH_MGMT_SERVER;
}
/* pick id from high and work down to low */
spin_lock_irqsave(&ha->vport_slock, flags);
for (; lid > 0; lid--) {
if (!test_bit(lid, vha->hw->loop_id_map)) {
set_bit(lid, vha->hw->loop_id_map);
loop_id = lid;
break;
}
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
return loop_id;
}
/*
* qla2x00_fabric_login
* Issue fabric login command.
*
* Input:
* ha = adapter block pointer.
* device = pointer to FC device type structure.
*
* Returns:
* 0 - Login successfully
* 1 - Login failed
* 2 - Initiator device
* 3 - Fatal error
*/
int
qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
uint16_t *next_loopid)
{
int rval;
int retry;
uint16_t tmp_loopid;
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct qla_hw_data *ha = vha->hw;
retry = 0;
tmp_loopid = 0;
for (;;) {
ql_dbg(ql_dbg_disc, vha, 0x2000,
"Trying Fabric Login w/loop id 0x%04x for port "
"%02x%02x%02x.\n",
fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
/* Login fcport on switch. */
rval = ha->isp_ops->fabric_login(vha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb, BIT_0);
if (rval != QLA_SUCCESS) {
return rval;
}
if (mb[0] == MBS_PORT_ID_USED) {
/*
* Device has another loop ID. The firmware team
* recommends the driver perform an implicit login with
* the specified ID again. The ID we just used is save
* here so we return with an ID that can be tried by
* the next login.
*/
retry++;
tmp_loopid = fcport->loop_id;
fcport->loop_id = mb[1];
ql_dbg(ql_dbg_disc, vha, 0x2001,
"Fabric Login: port in use - next loop "
"id=0x%04x, port id= %02x%02x%02x.\n",
fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
} else if (mb[0] == MBS_COMMAND_COMPLETE) {
/*
* Login succeeded.
*/
if (retry) {
/* A retry occurred before. */
*next_loopid = tmp_loopid;
} else {
/*
* No retry occurred before. Just increment the
* ID value for next login.
*/
*next_loopid = (fcport->loop_id + 1);
}
if (mb[1] & BIT_0) {
fcport->port_type = FCT_INITIATOR;
} else {
fcport->port_type = FCT_TARGET;
if (mb[1] & BIT_1) {
fcport->flags |= FCF_FCP2_DEVICE;
}
}
if (mb[10] & BIT_0)
fcport->supported_classes |= FC_COS_CLASS2;
if (mb[10] & BIT_1)
fcport->supported_classes |= FC_COS_CLASS3;
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
if (IS_FWI2_CAPABLE(ha)) {
if (mb[10] & BIT_7)
fcport->flags |=
FCF_CONF_COMP_SUPPORTED;
}
rval = QLA_SUCCESS;
break;
} else if (mb[0] == MBS_LOOP_ID_USED) {
/*
* Loop ID already used, try next loop ID.
*/
fcport->loop_id++;
rval = qla2x00_find_new_loop_id(vha, fcport);
if (rval != QLA_SUCCESS) {
/* Ran out of loop IDs to use */
break;
}
} else if (mb[0] == MBS_COMMAND_ERROR) {
/*
* Firmware possibly timed out during login. If NO
* retries are left to do then the device is declared
* dead.
*/
*next_loopid = fcport->loop_id;
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(vha, fcport, 1);
rval = 1;
break;
} else {
/*
* unrecoverable / not handled error
*/
ql_dbg(ql_dbg_disc, vha, 0x2002,
"Failed=%x port_id=%02x%02x%02x loop_id=%x "
"jiffies=%lx.\n", mb[0], fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->loop_id, jiffies);
*next_loopid = fcport->loop_id;
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_clear_loop_id(fcport);
fcport->login_retry = 0;
rval = 3;
break;
}
}
return (rval);
}
/*
* qla2x00_local_device_login
* Issue local device login command.
*
* Input:
* ha = adapter block pointer.
* loop_id = loop id of device to login to.
*
* Returns (Where's the #define!!!!):
* 0 - Login successfully
* 1 - Login failed
* 3 - Fatal error
*/
int
qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport)
{
int rval;
uint16_t mb[MAILBOX_REGISTER_COUNT];
memset(mb, 0, sizeof(mb));
rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0);
if (rval == QLA_SUCCESS) {
/* Interrogate mailbox registers for any errors */
if (mb[0] == MBS_COMMAND_ERROR)
rval = 1;
else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
/* device not in PCB table */
rval = 3;
}
return (rval);
}
/*
* qla2x00_loop_resync
* Resync with fibre channel devices.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success
*/
int
qla2x00_loop_resync(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
uint32_t wait_time;
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
if (vha->flags.online) {
if (!(rval = qla2x00_fw_ready(vha))) {
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
if (!IS_QLAFX00(vha->hw)) {
/*
* Issue a marker after FW becomes
* ready.
*/
qla2x00_marker(vha, vha->hw->base_qpair,
0, 0, MK_SYNC_ALL);
vha->marker_needed = 0;
}
/* Remap devices on Loop. */
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
if (IS_QLAFX00(vha->hw))
qlafx00_configure_devices(vha);
else
qla2x00_configure_loop(vha);
wait_time--;
} while (!atomic_read(&vha->loop_down_timer) &&
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
&& wait_time && (test_bit(LOOP_RESYNC_NEEDED,
&vha->dpc_flags)));
}
}
if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
return (QLA_FUNCTION_FAILED);
if (rval)
ql_dbg(ql_dbg_disc, vha, 0x206c,
"%s *** FAILED ***.\n", __func__);
return (rval);
}
/*
* qla2x00_perform_loop_resync
* Description: This function will set the appropriate flags and call
* qla2x00_loop_resync. If successful loop will be resynced
* Arguments : scsi_qla_host_t pointer
* returm : Success or Failure
*/
int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
{
int32_t rval = 0;
if (!test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) {
/*Configure the flags so that resync happens properly*/
atomic_set(&ha->loop_down_timer, 0);
if (!(ha->device_flags & DFLG_NO_CABLE)) {
atomic_set(&ha->loop_state, LOOP_UP);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
rval = qla2x00_loop_resync(ha);
} else
atomic_set(&ha->loop_state, LOOP_DEAD);
clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}
return rval;
}
/* Assumes idc_lock always held on entry */
void
qla83xx_reset_ownership(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
uint32_t drv_presence, drv_presence_mask;
uint32_t dev_part_info1, dev_part_info2, class_type;
uint32_t class_type_mask = 0x3;
uint16_t fcoe_other_function = 0xffff, i;
if (IS_QLA8044(ha)) {
drv_presence = qla8044_rd_direct(vha,
QLA8044_CRB_DRV_ACTIVE_INDEX);
dev_part_info1 = qla8044_rd_direct(vha,
QLA8044_CRB_DEV_PART_INFO_INDEX);
dev_part_info2 = qla8044_rd_direct(vha,
QLA8044_CRB_DEV_PART_INFO2);
} else {
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
}
for (i = 0; i < 8; i++) {
class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
(i != ha->portnum)) {
fcoe_other_function = i;
break;
}
}
if (fcoe_other_function == 0xffff) {
for (i = 0; i < 8; i++) {
class_type = ((dev_part_info2 >> (i * 4)) &
class_type_mask);
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
((i + 8) != ha->portnum)) {
fcoe_other_function = i + 8;
break;
}
}
}
/*
* Prepare drv-presence mask based on fcoe functions present.
* However consider only valid physical fcoe function numbers (0-15).
*/
drv_presence_mask = ~((1 << (ha->portnum)) |
((fcoe_other_function == 0xffff) ?
0 : (1 << (fcoe_other_function))));
/* We are the reset owner iff:
* - No other protocol drivers present.
* - This is the lowest among fcoe functions. */
if (!(drv_presence & drv_presence_mask) &&
(ha->portnum < fcoe_other_function)) {
ql_dbg(ql_dbg_p3p, vha, 0xb07f,
"This host is Reset owner.\n");
ha->flags.nic_core_reset_owner = 1;
}
}
static int
__qla83xx_set_drv_ack(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
struct qla_hw_data *ha = vha->hw;
uint32_t drv_ack;
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
if (rval == QLA_SUCCESS) {
drv_ack |= (1 << ha->portnum);
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
}
return rval;
}
static int
__qla83xx_clear_drv_ack(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
struct qla_hw_data *ha = vha->hw;
uint32_t drv_ack;
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
if (rval == QLA_SUCCESS) {
drv_ack &= ~(1 << ha->portnum);
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
}
return rval;
}
/* Assumes idc-lock always held on entry */
void
qla83xx_idc_audit(scsi_qla_host_t *vha, int audit_type)
{
struct qla_hw_data *ha = vha->hw;
uint32_t idc_audit_reg = 0, duration_secs = 0;
switch (audit_type) {
case IDC_AUDIT_TIMESTAMP:
ha->idc_audit_ts = (jiffies_to_msecs(jiffies) / 1000);
idc_audit_reg = (ha->portnum) |
(IDC_AUDIT_TIMESTAMP << 7) | (ha->idc_audit_ts << 8);
qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
break;
case IDC_AUDIT_COMPLETION:
duration_secs = ((jiffies_to_msecs(jiffies) -
jiffies_to_msecs(ha->idc_audit_ts)) / 1000);
idc_audit_reg = (ha->portnum) |
(IDC_AUDIT_COMPLETION << 7) | (duration_secs << 8);
qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
break;
default:
ql_log(ql_log_warn, vha, 0xb078,
"Invalid audit type specified.\n");
break;
}
}
/* Assumes idc_lock always held on entry */
static int
qla83xx_initiating_reset(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
uint32_t idc_control, dev_state;
__qla83xx_get_idc_control(vha, &idc_control);
if ((idc_control & QLA83XX_IDC_RESET_DISABLED)) {
ql_log(ql_log_info, vha, 0xb080,
"NIC Core reset has been disabled. idc-control=0x%x\n",
idc_control);
return QLA_FUNCTION_FAILED;
}
/* Set NEED-RESET iff in READY state and we are the reset-owner */
qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
if (ha->flags.nic_core_reset_owner && dev_state == QLA8XXX_DEV_READY) {
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
QLA8XXX_DEV_NEED_RESET);
ql_log(ql_log_info, vha, 0xb056, "HW State: NEED RESET.\n");
qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
} else {
ql_log(ql_log_info, vha, 0xb057, "HW State: %s.\n",
qdev_state(dev_state));
/* SV: XXX: Is timeout required here? */
/* Wait for IDC state change READY -> NEED_RESET */
while (dev_state == QLA8XXX_DEV_READY) {
qla83xx_idc_unlock(vha, 0);
msleep(200);
qla83xx_idc_lock(vha, 0);
qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
}
}
/* Send IDC ack by writing to drv-ack register */
__qla83xx_set_drv_ack(vha);
return QLA_SUCCESS;
}
int
__qla83xx_set_idc_control(scsi_qla_host_t *vha, uint32_t idc_control)
{
return qla83xx_wr_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
}
int
__qla83xx_get_idc_control(scsi_qla_host_t *vha, uint32_t *idc_control)
{
return qla83xx_rd_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
}
static int
qla83xx_check_driver_presence(scsi_qla_host_t *vha)
{
uint32_t drv_presence = 0;
struct qla_hw_data *ha = vha->hw;
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
if (drv_presence & (1 << ha->portnum))
return QLA_SUCCESS;
else
return QLA_TEST_FAILED;
}
int
qla83xx_nic_core_reset(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_p3p, vha, 0xb058,
"Entered %s().\n", __func__);
if (vha->device_flags & DFLG_DEV_FAILED) {
ql_log(ql_log_warn, vha, 0xb059,
"Device in unrecoverable FAILED state.\n");
return QLA_FUNCTION_FAILED;
}
qla83xx_idc_lock(vha, 0);
if (qla83xx_check_driver_presence(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0xb05a,
"Function=0x%x has been removed from IDC participation.\n",
ha->portnum);
rval = QLA_FUNCTION_FAILED;
goto exit;
}
qla83xx_reset_ownership(vha);
rval = qla83xx_initiating_reset(vha);
/*
* Perform reset if we are the reset-owner,
* else wait till IDC state changes to READY/FAILED.
*/
if (rval == QLA_SUCCESS) {
rval = qla83xx_idc_state_handler(vha);
if (rval == QLA_SUCCESS)
ha->flags.nic_core_hung = 0;
__qla83xx_clear_drv_ack(vha);
}
exit:
qla83xx_idc_unlock(vha, 0);
ql_dbg(ql_dbg_p3p, vha, 0xb05b, "Exiting %s.\n", __func__);
return rval;
}
int
qla2xxx_mctp_dump(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
int rval = QLA_FUNCTION_FAILED;
if (!IS_MCTP_CAPABLE(ha)) {
/* This message can be removed from the final version */
ql_log(ql_log_info, vha, 0x506d,
"This board is not MCTP capable\n");
return rval;
}
if (!ha->mctp_dump) {
ha->mctp_dump = dma_alloc_coherent(&ha->pdev->dev,
MCTP_DUMP_SIZE, &ha->mctp_dump_dma, GFP_KERNEL);
if (!ha->mctp_dump) {
ql_log(ql_log_warn, vha, 0x506e,
"Failed to allocate memory for mctp dump\n");
return rval;
}
}
#define MCTP_DUMP_STR_ADDR 0x00000000
rval = qla2x00_dump_mctp_data(vha, ha->mctp_dump_dma,
MCTP_DUMP_STR_ADDR, MCTP_DUMP_SIZE/4);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x506f,
"Failed to capture mctp dump\n");
} else {
ql_log(ql_log_info, vha, 0x5070,
"Mctp dump capture for host (%ld/%p).\n",
vha->host_no, ha->mctp_dump);
ha->mctp_dumped = 1;
}
if (!ha->flags.nic_core_reset_hdlr_active && !ha->portnum) {
ha->flags.nic_core_reset_hdlr_active = 1;
rval = qla83xx_restart_nic_firmware(vha);
if (rval)
/* NIC Core reset failed. */
ql_log(ql_log_warn, vha, 0x5071,
"Failed to restart nic firmware\n");
else
ql_dbg(ql_dbg_p3p, vha, 0xb084,
"Restarted NIC firmware successfully.\n");
ha->flags.nic_core_reset_hdlr_active = 0;
}
return rval;
}
/*
* qla2x00_quiesce_io
* Description: This function will block the new I/Os
* Its not aborting any I/Os as context
* is not destroyed during quiescence
* Arguments: scsi_qla_host_t
* return : void
*/
void
qla2x00_quiesce_io(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
struct scsi_qla_host *vp, *tvp;
unsigned long flags;
ql_dbg(ql_dbg_dpc, vha, 0x401d,
"Quiescing I/O - ha=%p.\n", ha);
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
spin_lock_irqsave(&ha->vport_slock, flags);
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
qla2x00_mark_all_devices_lost(vp);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
LOOP_DOWN_TIME);
}
/* Wait for pending cmds to complete */
WARN_ON_ONCE(qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST)
!= QLA_SUCCESS);
}
void
qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
struct scsi_qla_host *vp, *tvp;
unsigned long flags;
fc_port_t *fcport;
u16 i;
/* For ISP82XX, driver waits for completion of the commands.
* online flag should be set.
*/
if (!(IS_P3P_TYPE(ha)))
vha->flags.online = 0;
ha->flags.chip_reset_done = 0;
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
vha->qla_stats.total_isp_aborts++;
ql_log(ql_log_info, vha, 0x00af,
"Performing ISP error recovery - ha=%p.\n", ha);
ha->flags.purge_mbox = 1;
/* For ISP82XX, reset_chip is just disabling interrupts.
* Driver waits for the completion of the commands.
* the interrupts need to be enabled.
*/
if (!(IS_P3P_TYPE(ha)))
ha->isp_ops->reset_chip(vha);
ha->link_data_rate = PORT_SPEED_UNKNOWN;
SAVE_TOPO(ha);
ha->flags.rida_fmt2 = 0;
ha->flags.n2n_ae = 0;
ha->flags.lip_ae = 0;
ha->current_topology = 0;
QLA_FW_STOPPED(ha);
ha->flags.fw_init_done = 0;
ha->chip_reset++;
ha->base_qpair->chip_reset = ha->chip_reset;
ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0;
ha->base_qpair->prev_completion_cnt = 0;
for (i = 0; i < ha->max_qpairs; i++) {
if (ha->queue_pair_map[i]) {
ha->queue_pair_map[i]->chip_reset =
ha->base_qpair->chip_reset;
ha->queue_pair_map[i]->cmd_cnt =
ha->queue_pair_map[i]->cmd_completion_cnt = 0;
ha->base_qpair->prev_completion_cnt = 0;
}
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
/* purge MBox commands */
if (atomic_read(&ha->num_pend_mbx_stage3)) {
clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
complete(&ha->mbx_intr_comp);
}
i = 0;
while (atomic_read(&ha->num_pend_mbx_stage3) ||
atomic_read(&ha->num_pend_mbx_stage2) ||
atomic_read(&ha->num_pend_mbx_stage1)) {
msleep(20);
i++;
if (i > 50)
break;
}
ha->flags.purge_mbox = 0;
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha);
spin_lock_irqsave(&ha->vport_slock, flags);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
qla2x00_mark_all_devices_lost(vp);
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
LOOP_DOWN_TIME);
}
/* Clear all async request states across all VPs. */
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
fcport->scan_state = 0;
}
spin_lock_irqsave(&ha->vport_slock, flags);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
list_for_each_entry(fcport, &vp->vp_fcports, list)
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
/* Make sure for ISP 82XX IO DMA is complete */
if (IS_P3P_TYPE(ha)) {
qla82xx_chip_reset_cleanup(vha);
ql_log(ql_log_info, vha, 0x00b4,
"Done chip reset cleanup.\n");
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
/* Done waiting for pending commands. Reset online flag */
vha->flags.online = 0;
}
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
/* Requeue all commands in outstanding command list. */
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
/* memory barrier */
wmb();
}
/*
* qla2x00_abort_isp
* Resets ISP and aborts all outstanding commands.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success
*/
int
qla2x00_abort_isp(scsi_qla_host_t *vha)
{
int rval;
uint8_t status = 0;
struct qla_hw_data *ha = vha->hw;
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
struct scsi_qla_host *vp, *tvp;
struct req_que *req = ha->req_q_map[0];
unsigned long flags;
if (vha->flags.online) {
qla2x00_abort_isp_cleanup(vha);
vha->dport_status |= DPORT_DIAG_CHIP_RESET_IN_PROGRESS;
vha->dport_status &= ~DPORT_DIAG_IN_PROGRESS;
if (vha->hw->flags.port_isolated)
return status;
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x803f,
"ISP Abort - ISP reg disconnect, exiting.\n");
return status;
}
if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
ha->flags.chip_reset_done = 1;
vha->flags.online = 1;
status = 0;
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
return status;
}
if (IS_QLA8031(ha)) {
ql_dbg(ql_dbg_p3p, vha, 0xb05c,
"Clearing fcoe driver presence.\n");
if (qla83xx_clear_drv_presence(vha) != QLA_SUCCESS)
ql_dbg(ql_dbg_p3p, vha, 0xb073,
"Error while clearing DRV-Presence.\n");
}
if (unlikely(pci_channel_offline(ha->pdev) &&
ha->flags.pci_channel_io_perm_failure)) {
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
status = 0;
return status;
}
switch (vha->qlini_mode) {
case QLA2XXX_INI_MODE_DISABLED:
if (!qla_tgt_mode_enabled(vha))
return 0;
break;
case QLA2XXX_INI_MODE_DUAL:
if (!qla_dual_mode_enabled(vha) &&
!qla_ini_mode_enabled(vha))
return 0;
break;
case QLA2XXX_INI_MODE_ENABLED:
default:
break;
}
ha->isp_ops->get_flash_version(vha, req->ring);
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x803f,
"ISP Abort - ISP reg disconnect pre nvram config, exiting.\n");
return status;
}
ha->isp_ops->nvram_config(vha);
scsi: qla2xxx: Fix crash in PCIe error handling BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-29 08:52:25 +00:00
if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x803f,
"ISP Abort - ISP reg disconnect post nvmram config, exiting.\n");
return status;
}
if (!qla2x00_restart_isp(vha)) {
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
if (!atomic_read(&vha->loop_down_timer)) {
/*
* Issue marker command only when we are going
* to start the I/O .
*/
vha->marker_needed = 1;
}
vha->flags.online = 1;
ha->isp_ops->enable_intrs(ha);
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
if (IS_QLA81XX(ha) || IS_QLA8031(ha))
qla2x00_get_fw_version(vha);
if (ha->fce) {
ha->flags.fce_enabled = 1;
memset(ha->fce, 0,
fce_calc_size(ha->fce_bufs));
rval = qla2x00_enable_fce_trace(vha,
ha->fce_dma, ha->fce_bufs, ha->fce_mb,
&ha->fce_bufs);
if (rval) {
ql_log(ql_log_warn, vha, 0x8033,
"Unable to reinitialize FCE "
"(%d).\n", rval);
ha->flags.fce_enabled = 0;
}
}
if (ha->eft) {
memset(ha->eft, 0, EFT_SIZE);
rval = qla2x00_enable_eft_trace(vha,
ha->eft_dma, EFT_NUM_BUFFERS);
if (rval) {
ql_log(ql_log_warn, vha, 0x8034,
"Unable to reinitialize EFT "
"(%d).\n", rval);
}
}
} else { /* failed the ISP abort */
vha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
if (ha->isp_abort_cnt == 0) {
ql_log(ql_log_fatal, vha, 0x8035,
"ISP error recover failed - "
"board disabled.\n");
/*
* The next call disables the board
* completely.
*/
qla2x00_abort_isp_cleanup(vha);
vha->flags.online = 0;
clear_bit(ISP_ABORT_RETRY,
&vha->dpc_flags);
status = 0;
} else { /* schedule another ISP abort */
ha->isp_abort_cnt--;
ql_dbg(ql_dbg_taskm, vha, 0x8020,
"ISP abort - retry remaining %d.\n",
ha->isp_abort_cnt);
status = 1;
}
} else {
ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
ql_dbg(ql_dbg_taskm, vha, 0x8021,
"ISP error recovery - retrying (%d) "
"more times.\n", ha->isp_abort_cnt);
set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
status = 1;
}
}
}
if (vha->hw->flags.port_isolated) {
qla2x00_abort_isp_cleanup(vha);
return status;
}
if (!status) {
ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
qla2x00_configure_hba(vha);
spin_lock_irqsave(&ha->vport_slock, flags);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
if (vp->vp_idx) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
qla2x00_vp_abort_isp(vp);
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
if (IS_QLA8031(ha)) {
ql_dbg(ql_dbg_p3p, vha, 0xb05d,
"Setting back fcoe driver presence.\n");
if (qla83xx_set_drv_presence(vha) != QLA_SUCCESS)
ql_dbg(ql_dbg_p3p, vha, 0xb074,
"Error while setting DRV-Presence.\n");
}
} else {
ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n",
__func__);
}
return(status);
}
/*
* qla2x00_restart_isp
* restarts the ISP after a reset
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success
*/
static int
qla2x00_restart_isp(scsi_qla_host_t *vha)
{
int status;
struct qla_hw_data *ha = vha->hw;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
vha->flags.online = 0;
status = ha->isp_ops->chip_diag(vha);
if (status)
return status;
status = qla2x00_setup_chip(vha);
if (status)
return status;
}
status = qla2x00_init_rings(vha);
if (status)
return status;
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
ha->flags.chip_reset_done = 1;
/* Initialize the queues in use */
qla25xx_init_queues(ha);
status = qla2x00_fw_ready(vha);
if (status) {
/* if no cable then assume it's good */
return vha->device_flags & DFLG_NO_CABLE ? 0 : status;
}
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
return 0;
}
static int
qla25xx_init_queues(struct qla_hw_data *ha)
{
struct rsp_que *rsp = NULL;
struct req_que *req = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
int ret = -1;
int i;
for (i = 1; i < ha->max_rsp_queues; i++) {
rsp = ha->rsp_q_map[i];
if (rsp && test_bit(i, ha->rsp_qid_map)) {
rsp->options &= ~BIT_0;
ret = qla25xx_init_rsp_que(base_vha, rsp);
if (ret != QLA_SUCCESS)
ql_dbg(ql_dbg_init, base_vha, 0x00ff,
"%s Rsp que: %d init failed.\n",
__func__, rsp->id);
else
ql_dbg(ql_dbg_init, base_vha, 0x0100,
"%s Rsp que: %d inited.\n",
__func__, rsp->id);
}
}
for (i = 1; i < ha->max_req_queues; i++) {
req = ha->req_q_map[i];
if (req && test_bit(i, ha->req_qid_map)) {
/* Clear outstanding commands array. */
req->options &= ~BIT_0;
ret = qla25xx_init_req_que(base_vha, req);
if (ret != QLA_SUCCESS)
ql_dbg(ql_dbg_init, base_vha, 0x0101,
"%s Req que: %d init failed.\n",
__func__, req->id);
else
ql_dbg(ql_dbg_init, base_vha, 0x0102,
"%s Req que: %d inited.\n",
__func__, req->id);
}
}
return ret;
}
/*
* qla2x00_reset_adapter
* Reset adapter.
*
* Input:
* ha = adapter block pointer.
*/
int
qla2x00_reset_adapter(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
vha->flags.online = 0;
ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
rd_reg_word(&reg->hccr); /* PCI Posting. */
wrt_reg_word(&reg->hccr, HCCR_RELEASE_RISC);
rd_reg_word(&reg->hccr); /* PCI Posting. */
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
}
int
qla24xx_reset_adapter(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
if (IS_P3P_TYPE(ha))
return QLA_SUCCESS;
vha->flags.online = 0;
ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
wrt_reg_dword(&reg->hccr, HCCRX_SET_RISC_RESET);
rd_reg_dword(&reg->hccr);
wrt_reg_dword(&reg->hccr, HCCRX_REL_RISC_PAUSE);
rd_reg_dword(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (IS_NOPOLLING_TYPE(ha))
ha->isp_ops->enable_intrs(ha);
return QLA_SUCCESS;
}
/* On sparc systems, obtain port and node WWN from firmware
* properties.
*/
static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha,
struct nvram_24xx *nv)
{
#ifdef CONFIG_SPARC
struct qla_hw_data *ha = vha->hw;
struct pci_dev *pdev = ha->pdev;
struct device_node *dp = pci_device_to_OF_node(pdev);
const u8 *val;
int len;
val = of_get_property(dp, "port-wwn", &len);
if (val && len >= WWN_SIZE)
memcpy(nv->port_name, val, WWN_SIZE);
val = of_get_property(dp, "node-wwn", &len);
if (val && len >= WWN_SIZE)
memcpy(nv->node_name, val, WWN_SIZE);
#endif
}
int
qla24xx_nvram_config(scsi_qla_host_t *vha)
{
int rval;
struct init_cb_24xx *icb;
struct nvram_24xx *nv;
__le32 *dptr;
uint8_t *dptr1, *dptr2;
uint32_t chksum;
uint16_t cnt;
struct qla_hw_data *ha = vha->hw;
rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
nv = ha->nvram;
/* Determine NVRAM starting address. */
if (ha->port_no == 0) {
ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
ha->vpd_base = FA_NVRAM_VPD0_ADDR;
} else {
ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
ha->nvram_size = sizeof(*nv);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
ha->isp_ops->read_nvram(vha, ha->vpd,
ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
/* Get NVRAM data into cache and calculate checksum. */
dptr = (__force __le32 *)nv;
ha->isp_ops->read_nvram(vha, dptr, ha->nvram_base, ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a,
"Contents of NVRAM\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d,
nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
/* Reset NVRAM data. */
ql_log(ql_log_warn, vha, 0x006b,
"Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n",
chksum, nv->id, nv->nvram_version);
ql_dump_buffer(ql_dbg_init, vha, 0x006b, nv, sizeof(*nv));
ql_log(ql_log_warn, vha, 0x006c,
"Falling back to functioning (yet invalid -- WWPN) "
"defaults.\n");
/*
* Set default initialization control block.
*/
memset(nv, 0, ha->nvram_size);
nv->nvram_version = cpu_to_le16(ICB_VERSION);
nv->version = cpu_to_le16(ICB_VERSION);
nv->frame_payload_size = cpu_to_le16(2048);
nv->execution_throttle = cpu_to_le16(0xFFFF);
nv->exchange_count = cpu_to_le16(0);
nv->hard_address = cpu_to_le16(124);
nv->port_name[0] = 0x21;
nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
nv->port_name[5] = 0x1c;
nv->port_name[6] = 0x55;
nv->port_name[7] = 0x86;
nv->node_name[0] = 0x20;
nv->node_name[1] = 0x00;
nv->node_name[2] = 0x00;
nv->node_name[3] = 0xe0;
nv->node_name[4] = 0x8b;
nv->node_name[5] = 0x1c;
nv->node_name[6] = 0x55;
nv->node_name[7] = 0x86;
qla24xx_nvram_wwn_from_ofw(vha, nv);
nv->login_retry_count = cpu_to_le16(8);
nv->interrupt_delay_timer = cpu_to_le16(0);
nv->login_timeout = cpu_to_le16(0);
nv->firmware_options_1 =
cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
nv->firmware_options_2 = cpu_to_le32(2 << 4);
nv->firmware_options_2 |= cpu_to_le32(BIT_12);
nv->firmware_options_3 = cpu_to_le32(2 << 13);
nv->host_p = cpu_to_le32(BIT_11|BIT_10);
nv->efi_parameters = cpu_to_le32(0);
nv->reset_delay = 5;
nv->max_luns_per_target = cpu_to_le16(128);
nv->port_down_retry_count = cpu_to_le16(30);
nv->link_down_timeout = cpu_to_le16(30);
rval = 1;
}
qla2xxx: Add framework for async fabric discovery Currently code performs a full scan of the fabric for every RSCN. Its an expensive process in a noisy large SAN. This patch optimizes expensive fabric discovery process by scanning switch for the affected port when RSCN is received. Currently Initiator Mode code makes login/logout decision without knowledge of target mode. This causes driver and firmware to go out-of-sync. This framework synchronizes both initiator mode personality and target mode personality in making login/logout decision. This patch adds following capabilities in the driver - Send Notification Acknowledgement asynchronously. - Update session/fcport state asynchronously. - Create a session or fcport struct asynchronously. - Send GNL asynchronously. The command will ask FW to provide a list of FC Port entries FW knows about. - Send GPDB asynchronously. The command will ask FW to provide detail data of an FC Port FW knows about or perform ADISC to verify the state of the session. - Send GPNID asynchronously. The command will ask switch to provide WWPN for provided NPort ID. - Send GPSC asynchronously. The command will ask switch to provide registered port speed for provided WWPN. - Send GIDPN asynchronously. The command will ask the switch to provide Nport ID for provided WWPN. - In driver unload path, schedule all session for deletion and wait for deletion to complete before allowing driver unload to proceed. Signed-off-by: Quinn Tran <quinn.tran@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> [ bvanassche: fixed spelling in patch description ] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
2017-01-20 06:28:00 +00:00
if (qla_tgt_mode_enabled(vha)) {
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
/* Don't enable full login after initial LIP */
nv->firmware_options_1 &= cpu_to_le32(~BIT_13);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
/* Don't enable LIP full login for initiator */
nv->host_p &= cpu_to_le32(~BIT_10);
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
}
qlt_24xx_config_nvram_stage1(vha, nv);
/* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size);
/* Copy 1st segment. */
dptr1 = (uint8_t *)icb;
dptr2 = (uint8_t *)&nv->version;
cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
while (cnt--)
*dptr1++ = *dptr2++;
icb->login_retry_count = nv->login_retry_count;
icb->link_down_on_nos = nv->link_down_on_nos;
/* Copy 2nd segment. */
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
cnt = (uint8_t *)&icb->reserved_3 -
(uint8_t *)&icb->interrupt_delay_timer;
while (cnt--)
*dptr1++ = *dptr2++;
ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size);
/*
* Setup driver NVRAM options.
*/
qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
"QLA2462");
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
qlt_24xx_config_nvram_stage2(vha, icb);
if (nv->host_p & cpu_to_le32(BIT_15)) {
[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series Add LLD target mode for >= 24xx series HW. This code was originally based on external qla2x00t module based on 8.02.01-k4, and has been refactored to push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c. The implementation uses internal workqueues for I/O context submission into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for external interaction to allow qla2xxx LDD to function without direct target-core dependencies: It also enables qla_target.c usage within existing qla2xxx LLD code. This includes: *) Addition of target mode specific members to existing data structures in qla_def.h and struct qla_hw_data->tgt_ops using qla_target.h:struct qla_tgt_func_tmpl *) Addition of struct qla_tgt_func_tmpl and direct calls into qla_target.c logic w/ qlt_* prefixed functions. *) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and qla2x00_issue_marker() for handling request/response queue processing for target mode operation *) Addition of various qla_tgt_mode_enabled() logic checks in qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(), qla2x00_abort_isp(), qla24xx_modify_vp_config(), and qla2x00_vp_abort_isp(). By default the new qlini_mode module parameter is setting initiator-mode to 'enabled' in order for 'modprobe qla2xxx' to continue to function as expected in initiator only mode. Enabling target-mode operation will currently require a: modprobe qla2xxx qlini_mode="disabled" in order to explictly disabled initiator mode and allow target-mode to be enabled via tcm_qla2xxx configfs fabric callers. (nab: Convert to qlini_mode='enabled' by default in qla_target.c) (joern: Remove loop_id from qla_tgt_make_local_sess() arguments + Remove unused s_id + fix s_id endianness bug + simplify qla_tgt_abort_work) (gerard: fix section __exit mismatch in qla_tgt_exit) (arun: Capture ATIO queue during firmware dump + Send SCR in target mode + Target mode review comments) (roland: Don't create duplicate target sessions to address tearing down ACLs with IO in flight + Add missing call to qlt_fc_port_deleted call during qla2x00_schedule_rport_del timeout) Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2012-05-15 18:34:28 +00:00
/* Use alternate WWN? */
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
/* Prepare nodename */
if ((icb->firmware_options_1 & cpu_to_le32(BIT_14)) == 0) {
/*
* Firmware will apply the following mask if the nodename was
* not provided.
*/
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
icb->node_name[0] &= 0xF0;
}
/* Set host adapter parameters. */
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = 0;
ha->flags.enable_lip_full_login =
le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0;
ha->flags.enable_target_reset =
le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0;
ha->flags.enable_led_scheme = 0;
ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
sizeof(ha->fw_seriallink_options24));
/* save HBA serial number */
ha->serial0 = icb->port_name[5];
ha->serial1 = icb->port_name[6];
ha->serial2 = icb->port_name[7];
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
icb->execution_throttle = cpu_to_le16(0xFFFF);
ha->retry_count = le16_to_cpu(nv->login_retry_count);
/* Set minimum login_timeout to 4 seconds. */
if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
ha->loop_reset_delay = nv->reset_delay;
/* Link Down Timeout = 0:
*
* When Port Down timer expires we will start returning
* I/O's to OS with "DID_NO_CONNECT".
*
* Link Down Timeout != 0:
*
* The driver waits for the link to come up after link down
* before returning I/Os to OS with "DID_NO_CONNECT".
*/
if (le16_to_cpu(nv->link_down_timeout) == 0) {
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
} else {
ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - ha->link_down_timeout);
}
/* Need enough time to try and get the port back. */
ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
if (qlport_down_retry)
ha->port_down_retry_count = qlport_down_retry;
/* Set login_retry_count */
ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
if (ha->port_down_retry_count ==
le16_to_cpu(nv->port_down_retry_count) &&
ha->port_down_retry_count > 3)
ha->login_retry_count = ha->port_down_retry_count;
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
ha->login_retry_count = ha->port_down_retry_count;
if (ql2xloginretrycount)
ha->login_retry_count = ql2xloginretrycount;
/* N2N: driver will initiate Login instead of FW */
icb->firmware_options_3 |= cpu_to_le32(BIT_8);
/* Enable ZIO. */
if (!vha->flags.init_done) {
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
le16_to_cpu(icb->interrupt_delay_timer) : 2;
}
icb->firmware_options_2 &= cpu_to_le32(
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
if (ha->zio_mode != QLA_ZIO_DISABLED) {
ha->zio_mode = QLA_ZIO_MODE_6;
ql_log(ql_log_info, vha, 0x006f,
"ZIO mode %d enabled; timer delay (%d us).\n",
ha->zio_mode, ha->zio_timer * 100);
icb->firmware_options_2 |= cpu_to_le32(
(uint32_t)ha->zio_mode);
icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
}
if (rval) {
ql_log(ql_log_warn, vha, 0x0070,
"NVRAM configuration failed.\n");
}
return (rval);
}
static void
qla27xx_print_image(struct scsi_qla_host *vha, char *name,
struct qla27xx_image_status *image_status)
{
ql_dbg(ql_dbg_init, vha, 0x018b,
"%s %s: mask=%#02x gen=%#04x ver=%u.%u map=%#01x sum=%#08x sig=%#08x\n",
name, "status",
image_status->image_status_mask,
le16_to_cpu(image_status->generation),
image_status->ver_major,
image_status->ver_minor,
image_status->bitmap,
le32_to_cpu(image_status->checksum),
le32_to_cpu(image_status->signature));
}
static bool
qla28xx_check_aux_image_status_signature(
struct qla27xx_image_status *image_status)
{
ulong signature = le32_to_cpu(image_status->signature);
return signature != QLA28XX_AUX_IMG_STATUS_SIGN;
}
static bool
qla27xx_check_image_status_signature(struct qla27xx_image_status *image_status)
{
ulong signature = le32_to_cpu(image_status->signature);
return
signature != QLA27XX_IMG_STATUS_SIGN &&
signature != QLA28XX_IMG_STATUS_SIGN;
}
static ulong
qla27xx_image_status_checksum(struct qla27xx_image_status *image_status)
{
__le32 *p = (__force __le32 *)image_status;
uint n = sizeof(*image_status) / sizeof(*p);
uint32_t sum = 0;
for ( ; n--; p++)
sum += le32_to_cpup(p);
return sum;
}
static inline uint
qla28xx_component_bitmask(struct qla27xx_image_status *aux, uint bitmask)
{
return aux->bitmap & bitmask ?
QLA27XX_SECONDARY_IMAGE : QLA27XX_PRIMARY_IMAGE;
}
static void
qla28xx_component_status(
struct active_regions *active_regions, struct qla27xx_image_status *aux)
{
active_regions->aux.board_config =
qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_BOARD_CONFIG);
active_regions->aux.vpd_nvram =
qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_VPD_NVRAM);
active_regions->aux.npiv_config_0_1 =
qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_0_1);
active_regions->aux.npiv_config_2_3 =
qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_2_3);
active_regions->aux.nvme_params =
qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NVME_PARAMS);
}
static int
qla27xx_compare_image_generation(
struct qla27xx_image_status *pri_image_status,
struct qla27xx_image_status *sec_image_status)
{
/* calculate generation delta as uint16 (this accounts for wrap) */
int16_t delta =
le16_to_cpu(pri_image_status->generation) -
le16_to_cpu(sec_image_status->generation);
ql_dbg(ql_dbg_init, NULL, 0x0180, "generation delta = %d\n", delta);
return delta;
}
void
qla28xx_get_aux_images(
struct scsi_qla_host *vha, struct active_regions *active_regions)
{
struct qla_hw_data *ha = vha->hw;
struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status;
bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false;
if (!ha->flt_region_aux_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n");
goto check_sec_image;
}
qla24xx_read_flash_data(vha, (uint32_t *)&pri_aux_image_status,
ha->flt_region_aux_img_status_pri,
sizeof(pri_aux_image_status) >> 2);
qla27xx_print_image(vha, "Primary aux image", &pri_aux_image_status);
if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018b,
"Primary aux image signature (%#x) not valid\n",
le32_to_cpu(pri_aux_image_status.signature));
goto check_sec_image;
}
if (qla27xx_image_status_checksum(&pri_aux_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018c,
"Primary aux image checksum failed\n");
goto check_sec_image;
}
valid_pri_image = true;
if (pri_aux_image_status.image_status_mask & 1) {
ql_dbg(ql_dbg_init, vha, 0x018d,
"Primary aux image is active\n");
active_pri_image = true;
}
check_sec_image:
if (!ha->flt_region_aux_img_status_sec) {
ql_dbg(ql_dbg_init, vha, 0x018a,
"Secondary aux image not addressed\n");
goto check_valid_image;
}
qla24xx_read_flash_data(vha, (uint32_t *)&sec_aux_image_status,
ha->flt_region_aux_img_status_sec,
sizeof(sec_aux_image_status) >> 2);
qla27xx_print_image(vha, "Secondary aux image", &sec_aux_image_status);
if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018b,
"Secondary aux image signature (%#x) not valid\n",
le32_to_cpu(sec_aux_image_status.signature));
goto check_valid_image;
}
if (qla27xx_image_status_checksum(&sec_aux_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018c,
"Secondary aux image checksum failed\n");
goto check_valid_image;
}
valid_sec_image = true;
if (sec_aux_image_status.image_status_mask & 1) {
ql_dbg(ql_dbg_init, vha, 0x018d,
"Secondary aux image is active\n");
active_sec_image = true;
}
check_valid_image:
if (valid_pri_image && active_pri_image &&
valid_sec_image && active_sec_image) {
if (qla27xx_compare_image_generation(&pri_aux_image_status,
&sec_aux_image_status) >= 0) {
qla28xx_component_status(active_regions,
&pri_aux_image_status);
} else {
qla28xx_component_status(active_regions,
&sec_aux_image_status);
}
} else if (valid_pri_image && active_pri_image) {
qla28xx_component_status(active_regions, &pri_aux_image_status);
} else if (valid_sec_image && active_sec_image) {
qla28xx_component_status(active_regions, &sec_aux_image_status);
}
ql_dbg(ql_dbg_init, vha, 0x018f,
"aux images active: BCFG=%u VPD/NVR=%u NPIV0/1=%u NPIV2/3=%u, NVME=%u\n",
active_regions->aux.board_config,
active_regions->aux.vpd_nvram,
active_regions->aux.npiv_config_0_1,
active_regions->aux.npiv_config_2_3,
active_regions->aux.nvme_params);
}
void
qla27xx_get_active_image(struct scsi_qla_host *vha,
struct active_regions *active_regions)
{
struct qla_hw_data *ha = vha->hw;
struct qla27xx_image_status pri_image_status, sec_image_status;
bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false;
if (!ha->flt_region_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n");
goto check_sec_image;
}
if (qla24xx_read_flash_data(vha, (uint32_t *)&pri_image_status,
ha->flt_region_img_status_pri, sizeof(pri_image_status) >> 2) !=
QLA_SUCCESS) {
WARN_ON_ONCE(true);
goto check_sec_image;
}
qla27xx_print_image(vha, "Primary image", &pri_image_status);
if (qla27xx_check_image_status_signature(&pri_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018b,
"Primary image signature (%#x) not valid\n",
le32_to_cpu(pri_image_status.signature));
goto check_sec_image;
}
if (qla27xx_image_status_checksum(&pri_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018c,
"Primary image checksum failed\n");
goto check_sec_image;
}
valid_pri_image = true;
if (pri_image_status.image_status_mask & 1) {
ql_dbg(ql_dbg_init, vha, 0x018d,
"Primary image is active\n");
active_pri_image = true;
}
check_sec_image:
if (!ha->flt_region_img_status_sec) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Secondary image not addressed\n");
goto check_valid_image;
}
qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status),
ha->flt_region_img_status_sec, sizeof(sec_image_status) >> 2);
qla27xx_print_image(vha, "Secondary image", &sec_image_status);
if (qla27xx_check_image_status_signature(&sec_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018b,
"Secondary image signature (%#x) not valid\n",
le32_to_cpu(sec_image_status.signature));
goto check_valid_image;
}
if (qla27xx_image_status_checksum(&sec_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018c,
"Secondary image checksum failed\n");
goto check_valid_image;
}
valid_sec_image = true;
if (sec_image_status.image_status_mask & 1) {
ql_dbg(ql_dbg_init, vha, 0x018d,
"Secondary image is active\n");
active_sec_image = true;
}
check_valid_image:
if (valid_pri_image && active_pri_image)
active_regions->global = QLA27XX_PRIMARY_IMAGE;
if (valid_sec_image && active_sec_image) {
if (!active_regions->global ||
qla27xx_compare_image_generation(
&pri_image_status, &sec_image_status) < 0) {
active_regions->global = QLA27XX_SECONDARY_IMAGE;
}
}
ql_dbg(ql_dbg_init, vha, 0x018f, "active image %s (%u)\n",
active_regions->global == QLA27XX_DEFAULT_IMAGE ?
"default (boot/fw)" :
active_regions->global == QLA27XX_PRIMARY_IMAGE ?
"primary" :
active_regions->global == QLA27XX_SECONDARY_IMAGE ?
"secondary" : "invalid",
active_regions->global);
}
bool qla24xx_risc_firmware_invalid(uint32_t *dword)
{
return
!(dword[4] | dword[5] | dword[6] | dword[7]) ||
!(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]);
}
static int
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
uint32_t faddr)
{
int rval;
uint templates, segments, fragment;
ulong i;
uint j;
ulong dlen;
uint32_t *dcode;
uint32_t risc_addr, risc_size, risc_attr = 0;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct fwdt *fwdt = ha->fwdt;
ql_dbg(ql_dbg_init, vha, 0x008b,
"FW: Loading firmware from flash (%x).\n", faddr);
dcode = (uint32_t *)req->ring;
qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x008c,
"Unable to verify the integrity of flash firmware "
"image.\n");
ql_log(ql_log_fatal, vha, 0x008d,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
return QLA_FUNCTION_FAILED;
}
dcode = (uint32_t *)req->ring;
*srisc_addr = 0;
segments = FA_RISC_CODE_SEGMENTS;
for (j = 0; j < segments; j++) {
ql_dbg(ql_dbg_init, vha, 0x008d,
"-> Loading segment %u...\n", j);
qla24xx_read_flash_data(vha, dcode, faddr, 10);
risc_addr = be32_to_cpu((__force __be32)dcode[2]);
risc_size = be32_to_cpu((__force __be32)dcode[3]);
if (!*srisc_addr) {
*srisc_addr = risc_addr;
risc_attr = be32_to_cpu((__force __be32)dcode[9]);
}
dlen = ha->fw_transfer_size >> 2;
for (fragment = 0; risc_size; fragment++) {
if (dlen > risc_size)
dlen = risc_size;
ql_dbg(ql_dbg_init, vha, 0x008e,
"-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n",
fragment, risc_addr, faddr, dlen);
qla24xx_read_flash_data(vha, dcode, faddr, dlen);
for (i = 0; i < dlen; i++)
dcode[i] = swab32(dcode[i]);
rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x008f,
"-> Failed load firmware fragment %u.\n",
fragment);
return QLA_FUNCTION_FAILED;
}
faddr += dlen;
risc_addr += dlen;
risc_size -= dlen;
}
}
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_SUCCESS;
templates = (risc_attr & BIT_9) ? 2 : 1;
ql_dbg(ql_dbg_init, vha, 0x0160, "-> templates = %u\n", templates);
for (j = 0; j < templates; j++, fwdt++) {
vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
dcode = (uint32_t *)req->ring;
qla24xx_read_flash_data(vha, dcode, faddr, 7);
risc_size = be32_to_cpu((__force __be32)dcode[2]);
ql_dbg(ql_dbg_init, vha, 0x0161,
"-> fwdt%u template array at %#x (%#x dwords)\n",
j, faddr, risc_size);
if (!risc_size || !~risc_size) {
ql_dbg(ql_dbg_init, vha, 0x0162,
"-> fwdt%u failed to read array\n", j);
goto failed;
}
/* skip header and ignore checksum */
faddr += 7;
risc_size -= 8;
ql_dbg(ql_dbg_init, vha, 0x0163,
"-> fwdt%u template allocate template %#x words...\n",
j, risc_size);
fwdt->template = vmalloc(risc_size * sizeof(*dcode));
if (!fwdt->template) {
ql_log(ql_log_warn, vha, 0x0164,
"-> fwdt%u failed allocate template.\n", j);
goto failed;
}
dcode = fwdt->template;
qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
if (!qla27xx_fwdt_template_valid(dcode)) {
ql_log(ql_log_warn, vha, 0x0165,
"-> fwdt%u failed template validate\n", j);
goto failed;
}
dlen = qla27xx_fwdt_template_size(dcode);
ql_dbg(ql_dbg_init, vha, 0x0166,
"-> fwdt%u template size %#lx bytes (%#lx words)\n",
j, dlen, dlen / sizeof(*dcode));
if (dlen > risc_size * sizeof(*dcode)) {
ql_log(ql_log_warn, vha, 0x0167,
"-> fwdt%u template exceeds array (%-lu bytes)\n",
j, dlen - risc_size * sizeof(*dcode));
goto failed;
}
fwdt->length = dlen;
ql_dbg(ql_dbg_init, vha, 0x0168,
"-> fwdt%u loaded template ok\n", j);
faddr += risc_size + 1;
}
return QLA_SUCCESS;
failed:
vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
return QLA_SUCCESS;
}
#define QLA_FW_URL "http://ldriver.qlogic.com/firmware/"
int
qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
int i, fragment;
uint16_t *wcode;
__be16 *fwcode;
uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
struct fw_blob *blob;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
/* Load firmware blob. */
blob = qla2x00_request_firmware(vha);
if (!blob) {
ql_log(ql_log_info, vha, 0x0083,
"Firmware image unavailable.\n");
ql_log(ql_log_info, vha, 0x0084,
"Firmware images can be retrieved from: "QLA_FW_URL ".\n");
return QLA_FUNCTION_FAILED;
}
rval = QLA_SUCCESS;
wcode = (uint16_t *)req->ring;
*srisc_addr = 0;
fwcode = (__force __be16 *)blob->fw->data;
fwclen = 0;
/* Validate firmware image by checking version. */
if (blob->fw->size < 8 * sizeof(uint16_t)) {
ql_log(ql_log_fatal, vha, 0x0085,
"Unable to verify integrity of firmware image (%zd).\n",
blob->fw->size);
goto fail_fw_integrity;
}
for (i = 0; i < 4; i++)
wcode[i] = be16_to_cpu(fwcode[i + 4]);
if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
wcode[2] == 0 && wcode[3] == 0)) {
ql_log(ql_log_fatal, vha, 0x0086,
"Unable to verify integrity of firmware image.\n");
ql_log(ql_log_fatal, vha, 0x0087,
"Firmware data: %04x %04x %04x %04x.\n",
wcode[0], wcode[1], wcode[2], wcode[3]);
goto fail_fw_integrity;
}
seg = blob->segs;
while (*seg && rval == QLA_SUCCESS) {
risc_addr = *seg;
*srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
risc_size = be16_to_cpu(fwcode[3]);
/* Validate firmware image size. */
fwclen += risc_size * sizeof(uint16_t);
if (blob->fw->size < fwclen) {
ql_log(ql_log_fatal, vha, 0x0088,
"Unable to verify integrity of firmware image "
"(%zd).\n", blob->fw->size);
goto fail_fw_integrity;
}
fragment = 0;
while (risc_size > 0 && rval == QLA_SUCCESS) {
wlen = (uint16_t)(ha->fw_transfer_size >> 1);
if (wlen > risc_size)
wlen = risc_size;
ql_dbg(ql_dbg_init, vha, 0x0089,
"Loading risc segment@ risc addr %x number of "
"words 0x%x.\n", risc_addr, wlen);
for (i = 0; i < wlen; i++)
wcode[i] = swab16((__force u32)fwcode[i]);
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
wlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x008a,
"Failed to load segment %d of firmware.\n",
fragment);
break;
}
fwcode += wlen;
risc_addr += wlen;
risc_size -= wlen;
fragment++;
}
/* Next segment. */
seg++;
}
return rval;
fail_fw_integrity:
return QLA_FUNCTION_FAILED;
}
static int
qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
uint templates, segments, fragment;
uint32_t *dcode;
ulong dlen;
uint32_t risc_addr, risc_size, risc_attr = 0;
ulong i;
uint j;
struct fw_blob *blob;
__be32 *fwcode;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct fwdt *fwdt = ha->fwdt;
ql_dbg(ql_dbg_init, vha, 0x0090,
"-> FW: Loading via request-firmware.\n");
blob = qla2x00_request_firmware(vha);
if (!blob) {
ql_log(ql_log_warn, vha, 0x0092,
"-> Firmware file not found.\n");
return QLA_FUNCTION_FAILED;
}
fwcode = (__force __be32 *)blob->fw->data;
dcode = (__force uint32_t *)fwcode;
if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x0093,
"Unable to verify integrity of firmware image (%zd).\n",
blob->fw->size);
ql_log(ql_log_fatal, vha, 0x0095,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
return QLA_FUNCTION_FAILED;
}
dcode = (uint32_t *)req->ring;
*srisc_addr = 0;
segments = FA_RISC_CODE_SEGMENTS;
for (j = 0; j < segments; j++) {
ql_dbg(ql_dbg_init, vha, 0x0096,
"-> Loading segment %u...\n", j);
risc_addr = be32_to_cpu(fwcode[2]);
risc_size = be32_to_cpu(fwcode[3]);
if (!*srisc_addr) {
*srisc_addr = risc_addr;
risc_attr = be32_to_cpu(fwcode[9]);
}
dlen = ha->fw_transfer_size >> 2;
for (fragment = 0; risc_size; fragment++) {
if (dlen > risc_size)
dlen = risc_size;
ql_dbg(ql_dbg_init, vha, 0x0097,
"-> Loading fragment %u: %#x <- %#x (%#lx words)...\n",
fragment, risc_addr,
(uint32_t)(fwcode - (typeof(fwcode))blob->fw->data),
dlen);
for (i = 0; i < dlen; i++)
dcode[i] = swab32((__force u32)fwcode[i]);
rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x0098,
"-> Failed load firmware fragment %u.\n",
fragment);
return QLA_FUNCTION_FAILED;
}
fwcode += dlen;
risc_addr += dlen;
risc_size -= dlen;
}
}
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_SUCCESS;
templates = (risc_attr & BIT_9) ? 2 : 1;
ql_dbg(ql_dbg_init, vha, 0x0170, "-> templates = %u\n", templates);
for (j = 0; j < templates; j++, fwdt++) {
vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
risc_size = be32_to_cpu(fwcode[2]);
ql_dbg(ql_dbg_init, vha, 0x0171,
"-> fwdt%u template array at %#x (%#x dwords)\n",
j, (uint32_t)((void *)fwcode - (void *)blob->fw->data),
risc_size);
if (!risc_size || !~risc_size) {
ql_dbg(ql_dbg_init, vha, 0x0172,
"-> fwdt%u failed to read array\n", j);
goto failed;
}
/* skip header and ignore checksum */
fwcode += 7;
risc_size -= 8;
ql_dbg(ql_dbg_init, vha, 0x0173,
"-> fwdt%u template allocate template %#x words...\n",
j, risc_size);
fwdt->template = vmalloc(risc_size * sizeof(*dcode));
if (!fwdt->template) {
ql_log(ql_log_warn, vha, 0x0174,
"-> fwdt%u failed allocate template.\n", j);
goto failed;
}
dcode = fwdt->template;
for (i = 0; i < risc_size; i++)
dcode[i] = (__force u32)fwcode[i];
if (!qla27xx_fwdt_template_valid(dcode)) {
ql_log(ql_log_warn, vha, 0x0175,
"-> fwdt%u failed template validate\n", j);
goto failed;
}
dlen = qla27xx_fwdt_template_size(dcode);
ql_dbg(ql_dbg_init, vha, 0x0176,
"-> fwdt%u template size %#lx bytes (%#lx words)\n",
j, dlen, dlen / sizeof(*dcode));
if (dlen > risc_size * sizeof(*dcode)) {
ql_log(ql_log_warn, vha, 0x0177,
"-> fwdt%u template exceeds array (%-lu bytes)\n",
j, dlen - risc_size * sizeof(*dcode));
goto failed;
}
fwdt->length = dlen;
ql_dbg(ql_dbg_init, vha, 0x0178,
"-> fwdt%u loaded template ok\n", j);
fwcode += risc_size + 1;
}
return QLA_SUCCESS;
failed:
vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
return QLA_SUCCESS;
}
int
qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
if (ql2xfwloadbin == 1)
return qla81xx_load_risc(vha, srisc_addr);
/*
* FW Load priority:
* 1) Firmware via request-firmware interface (.bin file).
* 2) Firmware residing in flash.
*/
rval = qla24xx_load_risc_blob(vha, srisc_addr);
if (rval == QLA_SUCCESS)
return rval;
return qla24xx_load_risc_flash(vha, srisc_addr,
vha->hw->flt_region_fw);
}
int
qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
struct qla_hw_data *ha = vha->hw;
struct active_regions active_regions = { };
if (ql2xfwloadbin == 2)
goto try_blob_fw;
/* FW Load priority:
* 1) Firmware residing in flash.
* 2) Firmware via request-firmware interface (.bin file).
* 3) Golden-Firmware residing in flash -- (limited operation).
*/
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto try_primary_fw;
qla27xx_get_active_image(vha, &active_regions);
if (active_regions.global != QLA27XX_SECONDARY_IMAGE)
goto try_primary_fw;
ql_dbg(ql_dbg_init, vha, 0x008b,
"Loading secondary firmware image.\n");
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw_sec);
if (!rval)
return rval;
try_primary_fw:
ql_dbg(ql_dbg_init, vha, 0x008b,
"Loading primary firmware image.\n");
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
if (!rval)
return rval;
try_blob_fw:
rval = qla24xx_load_risc_blob(vha, srisc_addr);
if (!rval || !ha->flt_region_gold_fw)
return rval;
ql_log(ql_log_info, vha, 0x0099,
"Attempting to fallback to golden firmware.\n");
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
if (rval)
return rval;
ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n");
ha->flags.running_gold_fw = 1;
return rval;
}
void
qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
{
int ret, retries;
struct qla_hw_data *ha = vha->hw;
if (ha->flags.pci_channel_io_perm_failure)
return;
if (!IS_FWI2_CAPABLE(ha))
return;
if (!ha->fw_major_version)
return;
if (!ha->flags.fw_started)
return;
ret = qla2x00_stop_firmware(vha);
for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
ret != QLA_INVALID_COMMAND && retries ; retries--) {
ha->isp_ops->reset_chip(vha);
if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
continue;
if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
continue;
ql_log(ql_log_info, vha, 0x8015,
"Attempting retry of stop-firmware command.\n");
ret = qla2x00_stop_firmware(vha);
}
QLA_FW_STOPPED(ha);
ha->flags.fw_init_done = 0;
}
int
qla24xx_configure_vhba(scsi_qla_host_t *vha)
{
int rval = QLA_SUCCESS;
int rval2;
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
if (!vha->vp_idx)
return -EINVAL;
rval = qla2x00_fw_ready(base_vha);
if (rval == QLA_SUCCESS) {
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL);
}
vha->flags.management_server_logged_in = 0;
/* Login to SNS first */
rval2 = ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb,
BIT_1);
if (rval2 != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) {
if (rval2 == QLA_MEMORY_ALLOC_FAILED)
ql_dbg(ql_dbg_init, vha, 0x0120,
"Failed SNS login: loop_id=%x, rval2=%d\n",
NPH_SNS, rval2);
else
ql_dbg(ql_dbg_init, vha, 0x0103,
"Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
"mb[2]=%x mb[6]=%x mb[7]=%x.\n",
NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]);
return (QLA_FUNCTION_FAILED);
}
atomic_set(&vha->loop_down_timer, 0);
atomic_set(&vha->loop_state, LOOP_UP);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
rval = qla2x00_loop_resync(base_vha);
return rval;
}
/* 84XX Support **************************************************************/
static LIST_HEAD(qla_cs84xx_list);
static DEFINE_MUTEX(qla_cs84xx_mutex);
static struct qla_chip_state_84xx *
qla84xx_get_chip(struct scsi_qla_host *vha)
{
struct qla_chip_state_84xx *cs84xx;
struct qla_hw_data *ha = vha->hw;
mutex_lock(&qla_cs84xx_mutex);
/* Find any shared 84xx chip. */
list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
if (cs84xx->bus == ha->pdev->bus) {
kref_get(&cs84xx->kref);
goto done;
}
}
cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
if (!cs84xx)
goto done;
kref_init(&cs84xx->kref);
spin_lock_init(&cs84xx->access_lock);
mutex_init(&cs84xx->fw_update_mutex);
cs84xx->bus = ha->pdev->bus;
list_add_tail(&cs84xx->list, &qla_cs84xx_list);
done:
mutex_unlock(&qla_cs84xx_mutex);
return cs84xx;
}
static void
__qla84xx_chip_release(struct kref *kref)
{
struct qla_chip_state_84xx *cs84xx =
container_of(kref, struct qla_chip_state_84xx, kref);
mutex_lock(&qla_cs84xx_mutex);
list_del(&cs84xx->list);
mutex_unlock(&qla_cs84xx_mutex);
kfree(cs84xx);
}
void
qla84xx_put_chip(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
if (ha->cs84xx)
kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
}
static int
qla84xx_init_chip(scsi_qla_host_t *vha)
{
int rval;
uint16_t status[2];
struct qla_hw_data *ha = vha->hw;
mutex_lock(&ha->cs84xx->fw_update_mutex);
rval = qla84xx_verify_chip(vha, status);
mutex_unlock(&ha->cs84xx->fw_update_mutex);
return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED :
QLA_SUCCESS;
}
/* 81XX Support **************************************************************/
int
qla81xx_nvram_config(scsi_qla_host_t *vha)
{
int rval;
struct init_cb_81xx *icb;
struct nvram_81xx *nv;
__le32 *dptr;
uint8_t *dptr1, *dptr2;
uint32_t chksum;
uint16_t cnt;
struct qla_hw_data *ha = vha->hw;
uint32_t faddr;
struct active_regions active_regions = { };
rval = QLA_SUCCESS;
icb = (struct init_cb_81xx *)ha->init_cb;
nv = ha->nvram;
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(*nv);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
ha->vpd_size = FA_VPD_SIZE_82XX;
if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
qla28xx_get_aux_images(vha, &active_regions);
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
faddr = ha->flt_region_vpd;
if (IS_QLA28XX(ha)) {
if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
faddr = ha->flt_region_vpd_sec;
ql_dbg(ql_dbg_init, vha, 0x0110,
"Loading %s nvram image.\n",
active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
"primary" : "secondary");
}
ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, ha->vpd_size);
/* Get NVRAM data into cache and calculate checksum. */
faddr = ha->flt_region_nvram;
if (IS_QLA28XX(ha)) {
if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
faddr = ha->flt_region_nvram_sec;
}
ql_dbg(ql_dbg_init, vha, 0x0110,
"Loading %s nvram image.\n",
active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
"primary" : "secondary");
ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size);
dptr = (__force __le32 *)nv;
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
"Contents of NVRAM:\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
/* Reset NVRAM data. */
ql_log(ql_log_info, vha, 0x0073,
"Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n",
chksum, nv->id, le16_to_cpu(nv->nvram_version));
ql_dump_buffer(ql_dbg_init, vha, 0x0073, nv, sizeof(*nv));
ql_log(ql_log_info, vha, 0x0074,
"Falling back to functioning (yet invalid -- WWPN) "
"defaults.\n");
/*
* Set default initialization control block.
*/
memset(nv, 0, ha->nvram_size);
nv->nvram_version = cpu_to_le16(ICB_VERSION);
nv->version = cpu_to_le16(ICB_VERSION);
nv->frame_payload_size = cpu_to_le16(2048);
nv->execution_throttle = cpu_to_le16(0xFFFF);
nv->exchange_count = cpu_to_le16(0);
nv->port_name[0] = 0x21;
nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
nv->port_name[5] = 0x1c;
nv->port_name[6] = 0x55;
nv->port_name[7] = 0x86;
nv->node_name[0] = 0x20;
nv->node_name[1] = 0x00;
nv->node_name[2] = 0x00;
nv->node_name[3] = 0xe0;
nv->node_name[4] = 0x8b;
nv->node_name[5] = 0x1c;
nv->node_name[6] = 0x55;
nv->node_name[7] = 0x86;
nv->login_retry_count = cpu_to_le16(8);
nv->interrupt_delay_timer = cpu_to_le16(0);
nv->login_timeout = cpu_to_le16(0);
nv->firmware_options_1 =
cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
nv->firmware_options_2 = cpu_to_le32(2 << 4);
nv->firmware_options_2 |= cpu_to_le32(BIT_12);
nv->firmware_options_3 = cpu_to_le32(2 << 13);
nv->host_p = cpu_to_le32(BIT_11|BIT_10);
nv->efi_parameters = cpu_to_le32(0);
nv->reset_delay = 5;
nv->max_luns_per_target = cpu_to_le16(128);
nv->port_down_retry_count = cpu_to_le16(30);
nv->link_down_timeout = cpu_to_le16(180);
nv->enode_mac[0] = 0x00;
nv->enode_mac[1] = 0xC0;
nv->enode_mac[2] = 0xDD;
nv->enode_mac[3] = 0x04;
nv->enode_mac[4] = 0x05;
nv->enode_mac[5] = 0x06 + ha->port_no + 1;
rval = 1;
}
if (IS_T10_PI_CAPABLE(ha))
nv->frame_payload_size &= cpu_to_le16(~7);
qlt_81xx_config_nvram_stage1(vha, nv);
/* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size);
/* Copy 1st segment. */
dptr1 = (uint8_t *)icb;
dptr2 = (uint8_t *)&nv->version;
cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
while (cnt--)
*dptr1++ = *dptr2++;
icb->login_retry_count = nv->login_retry_count;
/* Copy 2nd segment. */
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
cnt = (uint8_t *)&icb->reserved_5 -
(uint8_t *)&icb->interrupt_delay_timer;
while (cnt--)
*dptr1++ = *dptr2++;
memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
/* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
icb->enode_mac[0] = 0x00;
icb->enode_mac[1] = 0xC0;
icb->enode_mac[2] = 0xDD;
icb->enode_mac[3] = 0x04;
icb->enode_mac[4] = 0x05;
icb->enode_mac[5] = 0x06 + ha->port_no + 1;
}
/* Use extended-initialization control block. */
memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb));
ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size);
/*
* Setup driver NVRAM options.
*/
qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
"QLE8XXX");
qlt_81xx_config_nvram_stage2(vha, icb);
/* Use alternate WWN? */
if (nv->host_p & cpu_to_le32(BIT_15)) {
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
/* Prepare nodename */
if ((icb->firmware_options_1 & cpu_to_le32(BIT_14)) == 0) {
/*
* Firmware will apply the following mask if the nodename was
* not provided.
*/
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
icb->node_name[0] &= 0xF0;
}
if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
if ((nv->enhanced_features & BIT_7) == 0)
ha->flags.scm_supported_a = 1;
}
/* Set host adapter parameters. */
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = 0;
ha->flags.enable_lip_full_login =
le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0;
ha->flags.enable_target_reset =
le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0;
ha->flags.enable_led_scheme = 0;
ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
/* save HBA serial number */
ha->serial0 = icb->port_name[5];
ha->serial1 = icb->port_name[6];
ha->serial2 = icb->port_name[7];
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
icb->execution_throttle = cpu_to_le16(0xFFFF);
ha->retry_count = le16_to_cpu(nv->login_retry_count);
/* Set minimum login_timeout to 4 seconds. */
if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
ha->loop_reset_delay = nv->reset_delay;
/* Link Down Timeout = 0:
*
* When Port Down timer expires we will start returning
* I/O's to OS with "DID_NO_CONNECT".
*
* Link Down Timeout != 0:
*
* The driver waits for the link to come up after link down
* before returning I/Os to OS with "DID_NO_CONNECT".
*/
if (le16_to_cpu(nv->link_down_timeout) == 0) {
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
} else {
ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
ha->loop_down_abort_time =
(LOOP_DOWN_TIME - ha->link_down_timeout);
}
/* Need enough time to try and get the port back. */
ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
if (qlport_down_retry)
ha->port_down_retry_count = qlport_down_retry;
/* Set login_retry_count */
ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
if (ha->port_down_retry_count ==
le16_to_cpu(nv->port_down_retry_count) &&
ha->port_down_retry_count > 3)
ha->login_retry_count = ha->port_down_retry_count;
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
ha->login_retry_count = ha->port_down_retry_count;
if (ql2xloginretrycount)
ha->login_retry_count = ql2xloginretrycount;
/* if not running MSI-X we need handshaking on interrupts */
if (!vha->hw->flags.msix_enabled &&
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)))
icb->firmware_options_2 |= cpu_to_le32(BIT_22);
/* Enable ZIO. */
if (!vha->flags.init_done) {
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
le16_to_cpu(icb->interrupt_delay_timer) : 2;
}
icb->firmware_options_2 &= cpu_to_le32(
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
vha->flags.process_response_queue = 0;
if (ha->zio_mode != QLA_ZIO_DISABLED) {
ha->zio_mode = QLA_ZIO_MODE_6;
ql_log(ql_log_info, vha, 0x0075,
"ZIO mode %d enabled; timer delay (%d us).\n",
ha->zio_mode,
ha->zio_timer * 100);
icb->firmware_options_2 |= cpu_to_le32(
(uint32_t)ha->zio_mode);
icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
vha->flags.process_response_queue = 1;
}
/* enable RIDA Format2 */
icb->firmware_options_3 |= cpu_to_le32(BIT_0);
/* N2N: driver will initiate Login instead of FW */
icb->firmware_options_3 |= cpu_to_le32(BIT_8);
/* Determine NVMe/FCP priority for target ports */
ha->fc4_type_priority = qla2xxx_get_fc4_priority(vha);
if (rval) {
ql_log(ql_log_warn, vha, 0x0076,
"NVRAM configuration failed.\n");
}
return (rval);
}
int
qla82xx_restart_isp(scsi_qla_host_t *vha)
{
int status, rval;
struct qla_hw_data *ha = vha->hw;
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
struct scsi_qla_host *vp, *tvp;
unsigned long flags;
status = qla2x00_init_rings(vha);
if (!status) {
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
ha->flags.chip_reset_done = 1;
status = qla2x00_fw_ready(vha);
if (!status) {
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL);
vha->flags.online = 1;
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
/* if no cable then assume it's good */
if ((vha->device_flags & DFLG_NO_CABLE))
status = 0;
}
if (!status) {
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
if (!atomic_read(&vha->loop_down_timer)) {
/*
* Issue marker command only when we are going
* to start the I/O .
*/
vha->marker_needed = 1;
}
ha->isp_ops->enable_intrs(ha);
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
/* Update the firmware version */
status = qla82xx_check_md_needed(vha);
if (ha->fce) {
ha->flags.fce_enabled = 1;
memset(ha->fce, 0,
fce_calc_size(ha->fce_bufs));
rval = qla2x00_enable_fce_trace(vha,
ha->fce_dma, ha->fce_bufs, ha->fce_mb,
&ha->fce_bufs);
if (rval) {
ql_log(ql_log_warn, vha, 0x8001,
"Unable to reinitialize FCE (%d).\n",
rval);
ha->flags.fce_enabled = 0;
}
}
if (ha->eft) {
memset(ha->eft, 0, EFT_SIZE);
rval = qla2x00_enable_eft_trace(vha,
ha->eft_dma, EFT_NUM_BUFFERS);
if (rval) {
ql_log(ql_log_warn, vha, 0x8010,
"Unable to reinitialize EFT (%d).\n",
rval);
}
}
}
if (!status) {
ql_dbg(ql_dbg_taskm, vha, 0x8011,
"qla82xx_restart_isp succeeded.\n");
spin_lock_irqsave(&ha->vport_slock, flags);
scsi: qla2xxx: Fix unsafe removal from linked list On NPIV delete, the VPort is taken off a linked list in an unsafe manner. The check for VPort refcount should be done behind lock before taking off the element. [ 2733.016907] general protection fault: 0000 [#1] SMP NOPTI [ 2733.016908] qla2xxx [0000:22:00.1]-7088:27: VP[4] deleted. [ 2733.016912] CPU: 22 PID: 23481 Comm: qla2xxx_15_dpc Kdump: loaded Tainted: G OE KX 5.3.18-47-default #1 SLE15-SP3 [ 2733.016914] Hardware name: Dell Inc. PowerEdge R7525/0PYVT1, BIOS 2.1.4 02/17/2021 [ 2733.016929] RIP: 0010:qla2x00_abort_isp+0x90/0x850 [qla2xxx] [ 2733.016933] RSP: 0018:ffffb9cfc91efe98 EFLAGS: 00010087 [ 2733.016935] RAX: 0000000000000292 RBX: dead000000000100 RCX: 0000000000000000 [ 2733.016936] RDX: 0000000000000001 RSI: ffff944bfeb99558 RDI: ffff944bfc4b4488 [ 2733.016937] RBP: ffff944bfc4b2868 R08: 00000000000187a2 R09: 0000000000000001 [ 2733.016937] R10: ffffb9cfc91efcc8 R11: 0000000000000001 R12: ffff944bfc4b4000 [ 2733.016938] R13: ffff944bfc4b4870 R14: ffff944bfc4b4488 R15: ffff944bda895c80 [ 2733.016939] FS: 0000000000000000(0000) GS:ffff944bfeb80000(0000) knlGS:0000000000000000 [ 2733.016940] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2733.016940] CR2: 00007fc173e74458 CR3: 0000001ff57de000 CR4: 0000000000350ee0 [ 2733.016941] Call Trace: [ 2733.016951] qla2xxx_pci_error_detected+0x190/0x190 [qla2xxx] [ 2733.016957] qla2x00_do_dpc+0x560/0xa10 [qla2xxx] [ 2733.016962] kthread+0x10d/0x130 [ 2733.016963] kthread_park+0xa0/0xa0 [ 2733.016966] ret_from_fork+0x22/0x40 Link: https://lore.kernel.org/r/20210810043720.1137-9-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-08-10 04:37:14 +00:00
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
if (vp->vp_idx) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
qla2x00_vp_abort_isp(vp);
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
} else {
ql_log(ql_log_warn, vha, 0x8016,
"qla82xx_restart_isp **** FAILED ****.\n");
}
return status;
}
/*
* qla24xx_get_fcp_prio
* Gets the fcp cmd priority value for the logged in port.
* Looks for a match of the port descriptors within
* each of the fcp prio config entries. If a match is found,
* the tag (priority) value is returned.
*
* Input:
* vha = scsi host structure pointer.
* fcport = port structure pointer.
*
* Return:
* non-zero (if found)
* -1 (if not found)
*
* Context:
* Kernel context
*/
static int
qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
{
int i, entries;
uint8_t pid_match, wwn_match;
int priority;
uint32_t pid1, pid2;
uint64_t wwn1, wwn2;
struct qla_fcp_prio_entry *pri_entry;
struct qla_hw_data *ha = vha->hw;
if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
return -1;
priority = -1;
entries = ha->fcp_prio_cfg->num_entries;
pri_entry = &ha->fcp_prio_cfg->entry[0];
for (i = 0; i < entries; i++) {
pid_match = wwn_match = 0;
if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) {
pri_entry++;
continue;
}
/* check source pid for a match */
if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) {
pid1 = pri_entry->src_pid & INVALID_PORT_ID;
pid2 = vha->d_id.b24 & INVALID_PORT_ID;
if (pid1 == INVALID_PORT_ID)
pid_match++;
else if (pid1 == pid2)
pid_match++;
}
/* check destination pid for a match */
if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) {
pid1 = pri_entry->dst_pid & INVALID_PORT_ID;
pid2 = fcport->d_id.b24 & INVALID_PORT_ID;
if (pid1 == INVALID_PORT_ID)
pid_match++;
else if (pid1 == pid2)
pid_match++;
}
/* check source WWN for a match */
if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) {
wwn1 = wwn_to_u64(vha->port_name);
wwn2 = wwn_to_u64(pri_entry->src_wwpn);
if (wwn2 == (uint64_t)-1)
wwn_match++;
else if (wwn1 == wwn2)
wwn_match++;
}
/* check destination WWN for a match */
if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) {
wwn1 = wwn_to_u64(fcport->port_name);
wwn2 = wwn_to_u64(pri_entry->dst_wwpn);
if (wwn2 == (uint64_t)-1)
wwn_match++;
else if (wwn1 == wwn2)
wwn_match++;
}
if (pid_match == 2 || wwn_match == 2) {
/* Found a matching entry */
if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
priority = pri_entry->tag;
break;
}
pri_entry++;
}
return priority;
}
/*
* qla24xx_update_fcport_fcp_prio
* Activates fcp priority for the logged in fc port
*
* Input:
* vha = scsi host structure pointer.
* fcp = port structure pointer.
*
* Return:
* QLA_SUCCESS or QLA_FUNCTION_FAILED
*
* Context:
* Kernel context.
*/
int
qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
{
int ret;
int priority;
uint16_t mb[5];
if (fcport->port_type != FCT_TARGET ||
fcport->loop_id == FC_NO_LOOP_ID)
return QLA_FUNCTION_FAILED;
priority = qla24xx_get_fcp_prio(vha, fcport);
if (priority < 0)
return QLA_FUNCTION_FAILED;
if (IS_P3P_TYPE(vha->hw)) {
fcport->fcp_prio = priority & 0xf;
return QLA_SUCCESS;
}
ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb);
if (ret == QLA_SUCCESS) {
if (fcport->fcp_prio != priority)
ql_dbg(ql_dbg_user, vha, 0x709e,
"Updated FCP_CMND priority - value=%d loop_id=%d "
"port_id=%02x%02x%02x.\n", priority,
fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
fcport->fcp_prio = priority & 0xf;
} else
ql_dbg(ql_dbg_user, vha, 0x704f,
"Unable to update FCP_CMND priority - ret=0x%x for "
"loop_id=%d port_id=%02x%02x%02x.\n", ret, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
return ret;
}
/*
* qla24xx_update_all_fcp_prio
* Activates fcp priority for all the logged in ports
*
* Input:
* ha = adapter block pointer.
*
* Return:
* QLA_SUCCESS or QLA_FUNCTION_FAILED
*
* Context:
* Kernel context.
*/
int
qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha)
{
int ret;
fc_port_t *fcport;
ret = QLA_FUNCTION_FAILED;
/* We need to set priority for all logged in ports */
list_for_each_entry(fcport, &vha->vp_fcports, list)
ret = qla24xx_update_fcport_fcp_prio(vha, fcport);
return ret;
}
struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
int vp_idx, bool startqp)
{
int rsp_id = 0;
int req_id = 0;
int i;
struct qla_hw_data *ha = vha->hw;
uint16_t qpair_id = 0;
struct qla_qpair *qpair = NULL;
struct qla_msix_entry *msix;
if (!(ha->fw_attributes & BIT_6) || !ha->flags.msix_enabled) {
ql_log(ql_log_warn, vha, 0x00181,
"FW/Driver is not multi-queue capable.\n");
return NULL;
}
if (ql2xmqsupport || ql2xnvmeenable) {
qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL);
if (qpair == NULL) {
ql_log(ql_log_warn, vha, 0x0182,
"Failed to allocate memory for queue pair.\n");
return NULL;
}
qpair->hw = vha->hw;
qpair->vha = vha;
qpair->qp_lock_ptr = &qpair->qp_lock;
spin_lock_init(&qpair->qp_lock);
qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0;
/* Assign available que pair id */
mutex_lock(&ha->mq_lock);
qpair_id = find_first_zero_bit(ha->qpair_qid_map, ha->max_qpairs);
if (ha->num_qpairs >= ha->max_qpairs) {
mutex_unlock(&ha->mq_lock);
ql_log(ql_log_warn, vha, 0x0183,
"No resources to create additional q pair.\n");
goto fail_qid_map;
}
ha->num_qpairs++;
set_bit(qpair_id, ha->qpair_qid_map);
ha->queue_pair_map[qpair_id] = qpair;
qpair->id = qpair_id;
qpair->vp_idx = vp_idx;
qpair->fw_started = ha->flags.fw_started;
INIT_LIST_HEAD(&qpair->hints_list);
qpair->chip_reset = ha->base_qpair->chip_reset;
qpair->enable_class_2 = ha->base_qpair->enable_class_2;
qpair->enable_explicit_conf =
ha->base_qpair->enable_explicit_conf;
for (i = 0; i < ha->msix_count; i++) {
msix = &ha->msix_entries[i];
if (msix->in_use)
continue;
qpair->msix = msix;
ql_dbg(ql_dbg_multiq, vha, 0xc00f,
"Vector %x selected for qpair\n", msix->vector);
break;
}
if (!qpair->msix) {
ql_log(ql_log_warn, vha, 0x0184,
"Out of MSI-X vectors!.\n");
goto fail_msix;
}
qpair->msix->in_use = 1;
list_add_tail(&qpair->qp_list_elem, &vha->qp_list);
qpair->pdev = ha->pdev;
if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
mutex_unlock(&ha->mq_lock);
/* Create response queue first */
rsp_id = qla25xx_create_rsp_que(ha, 0, 0, 0, qpair, startqp);
if (!rsp_id) {
ql_log(ql_log_warn, vha, 0x0185,
"Failed to create response queue.\n");
goto fail_rsp;
}
qpair->rsp = ha->rsp_q_map[rsp_id];
/* Create request queue */
req_id = qla25xx_create_req_que(ha, 0, vp_idx, 0, rsp_id, qos,
startqp);
if (!req_id) {
ql_log(ql_log_warn, vha, 0x0186,
"Failed to create request queue.\n");
goto fail_req;
}
qpair->req = ha->req_q_map[req_id];
qpair->rsp->req = qpair->req;
qpair->rsp->qpair = qpair;
if (!qpair->cpu_mapped)
qla_cpu_update(qpair, raw_smp_processor_id());
if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4)
qpair->difdix_supported = 1;
}
qpair->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
if (!qpair->srb_mempool) {
ql_log(ql_log_warn, vha, 0xd036,
"Failed to create srb mempool for qpair %d\n",
qpair->id);
goto fail_mempool;
}
if (qla_create_buf_pool(vha, qpair)) {
ql_log(ql_log_warn, vha, 0xd036,
"Failed to initialize buf pool for qpair %d\n",
qpair->id);
goto fail_bufpool;
}
/* Mark as online */
qpair->online = 1;
if (!vha->flags.qpairs_available)
vha->flags.qpairs_available = 1;
ql_dbg(ql_dbg_multiq, vha, 0xc00d,
"Request/Response queue pair created, id %d\n",
qpair->id);
ql_dbg(ql_dbg_init, vha, 0x0187,
"Request/Response queue pair created, id %d\n",
qpair->id);
}
return qpair;
fail_bufpool:
mempool_destroy(qpair->srb_mempool);
fail_mempool:
qla25xx_delete_req_que(vha, qpair->req);
fail_req:
qla25xx_delete_rsp_que(vha, qpair->rsp);
fail_rsp:
mutex_lock(&ha->mq_lock);
qpair->msix->in_use = 0;
list_del(&qpair->qp_list_elem);
if (list_empty(&vha->qp_list))
vha->flags.qpairs_available = 0;
fail_msix:
ha->queue_pair_map[qpair_id] = NULL;
clear_bit(qpair_id, ha->qpair_qid_map);
ha->num_qpairs--;
mutex_unlock(&ha->mq_lock);
fail_qid_map:
kfree(qpair);
return NULL;
}
int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair)
{
int ret = QLA_FUNCTION_FAILED;
struct qla_hw_data *ha = qpair->hw;
qpair->delete_in_progress = 1;
qla_free_buf_pool(qpair);
ret = qla25xx_delete_req_que(vha, qpair->req);
if (ret != QLA_SUCCESS)
goto fail;
ret = qla25xx_delete_rsp_que(vha, qpair->rsp);
if (ret != QLA_SUCCESS)
goto fail;
mutex_lock(&ha->mq_lock);
ha->queue_pair_map[qpair->id] = NULL;
clear_bit(qpair->id, ha->qpair_qid_map);
ha->num_qpairs--;
list_del(&qpair->qp_list_elem);
if (list_empty(&vha->qp_list)) {
vha->flags.qpairs_available = 0;
vha->flags.qpairs_req_created = 0;
vha->flags.qpairs_rsp_created = 0;
}
mempool_destroy(qpair->srb_mempool);
kfree(qpair);
mutex_unlock(&ha->mq_lock);
return QLA_SUCCESS;
fail:
return ret;
}
uint64_t
qla2x00_count_set_bits(uint32_t num)
{
/* Brian Kernighan's Algorithm */
u64 count = 0;
while (num) {
num &= (num - 1);
count++;
}
return count;
}
uint64_t
qla2x00_get_num_tgts(scsi_qla_host_t *vha)
{
fc_port_t *f, *tf;
u64 count = 0;
f = NULL;
tf = NULL;
list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
if (f->port_type != FCT_TARGET)
continue;
count++;
}
return count;
}
int qla2xxx_reset_stats(struct Scsi_Host *host, u32 flags)
{
scsi_qla_host_t *vha = shost_priv(host);
fc_port_t *fcport = NULL;
unsigned long int_flags;
if (flags & QLA2XX_HW_ERROR)
vha->hw_err_cnt = 0;
if (flags & QLA2XX_SHT_LNK_DWN)
vha->short_link_down_cnt = 0;
if (flags & QLA2XX_INT_ERR)
vha->interface_err_cnt = 0;
if (flags & QLA2XX_CMD_TIMEOUT)
vha->cmd_timeout_cnt = 0;
if (flags & QLA2XX_RESET_CMD_ERR)
vha->reset_cmd_err_cnt = 0;
if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->tgt_short_link_down_cnt = 0;
fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
}
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
}
vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
return 0;
}
int qla2xxx_start_stats(struct Scsi_Host *host, u32 flags)
{
return qla2xxx_reset_stats(host, flags);
}
int qla2xxx_stop_stats(struct Scsi_Host *host, u32 flags)
{
return qla2xxx_reset_stats(host, flags);
}
int qla2xxx_get_ini_stats(struct Scsi_Host *host, u32 flags,
void *data, u64 size)
{
scsi_qla_host_t *vha = shost_priv(host);
struct ql_vnd_host_stats_resp *resp = (struct ql_vnd_host_stats_resp *)data;
struct ql_vnd_stats *rsp_data = &resp->stats;
u64 ini_entry_count = 0;
u64 i = 0;
u64 entry_count = 0;
u64 num_tgt = 0;
u32 tmp_stat_type = 0;
fc_port_t *fcport = NULL;
unsigned long int_flags;
/* Copy stat type to work on it */
tmp_stat_type = flags;
if (tmp_stat_type & BIT_17) {
num_tgt = qla2x00_get_num_tgts(vha);
/* unset BIT_17 */
tmp_stat_type &= ~(1 << 17);
}
ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
entry_count = ini_entry_count + num_tgt;
rsp_data->entry_count = entry_count;
i = 0;
if (flags & QLA2XX_HW_ERROR) {
rsp_data->entry[i].stat_type = QLA2XX_HW_ERROR;
rsp_data->entry[i].tgt_num = 0x0;
rsp_data->entry[i].cnt = vha->hw_err_cnt;
i++;
}
if (flags & QLA2XX_SHT_LNK_DWN) {
rsp_data->entry[i].stat_type = QLA2XX_SHT_LNK_DWN;
rsp_data->entry[i].tgt_num = 0x0;
rsp_data->entry[i].cnt = vha->short_link_down_cnt;
i++;
}
if (flags & QLA2XX_INT_ERR) {
rsp_data->entry[i].stat_type = QLA2XX_INT_ERR;
rsp_data->entry[i].tgt_num = 0x0;
rsp_data->entry[i].cnt = vha->interface_err_cnt;
i++;
}
if (flags & QLA2XX_CMD_TIMEOUT) {
rsp_data->entry[i].stat_type = QLA2XX_CMD_TIMEOUT;
rsp_data->entry[i].tgt_num = 0x0;
rsp_data->entry[i].cnt = vha->cmd_timeout_cnt;
i++;
}
if (flags & QLA2XX_RESET_CMD_ERR) {
rsp_data->entry[i].stat_type = QLA2XX_RESET_CMD_ERR;
rsp_data->entry[i].tgt_num = 0x0;
rsp_data->entry[i].cnt = vha->reset_cmd_err_cnt;
i++;
}
/* i will continue from previous loop, as target
* entries are after initiator
*/
if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->port_type != FCT_TARGET)
continue;
if (!fcport->rport)
continue;
rsp_data->entry[i].stat_type = QLA2XX_TGT_SHT_LNK_DOWN;
rsp_data->entry[i].tgt_num = fcport->rport->number;
rsp_data->entry[i].cnt = fcport->tgt_short_link_down_cnt;
i++;
}
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
}
resp->status = EXT_STATUS_OK;
return 0;
}
int qla2xxx_get_tgt_stats(struct Scsi_Host *host, u32 flags,
struct fc_rport *rport, void *data, u64 size)
{
struct ql_vnd_tgt_stats_resp *tgt_data = data;
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
tgt_data->status = 0;
tgt_data->stats.entry_count = 1;
tgt_data->stats.entry[0].stat_type = flags;
tgt_data->stats.entry[0].tgt_num = rport->number;
tgt_data->stats.entry[0].cnt = fcport->tgt_short_link_down_cnt;
return 0;
}
int qla2xxx_disable_port(struct Scsi_Host *host)
{
scsi_qla_host_t *vha = shost_priv(host);
vha->hw->flags.port_isolated = 1;
if (qla2x00_isp_reg_stat(vha->hw)) {
ql_log(ql_log_info, vha, 0x9006,
"PCI/Register disconnect, exiting.\n");
qla_pci_set_eeh_busy(vha);
return FAILED;
}
if (qla2x00_chip_is_down(vha))
return 0;
if (vha->flags.online) {
qla2x00_abort_isp_cleanup(vha);
qla2x00_wait_for_sess_deletion(vha);
}
return 0;
}
int qla2xxx_enable_port(struct Scsi_Host *host)
{
scsi_qla_host_t *vha = shost_priv(host);
if (qla2x00_isp_reg_stat(vha->hw)) {
ql_log(ql_log_info, vha, 0x9001,
"PCI/Register disconnect, exiting.\n");
qla_pci_set_eeh_busy(vha);
return FAILED;
}
vha->hw->flags.port_isolated = 0;
/* Set the flag to 1, so that isp_abort can proceed */
vha->flags.online = 1;
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
return 0;
}