2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2005-10-28 02:10:08 +08:00
|
|
|
* QLogic Fibre Channel HBA Driver
|
2014-04-12 04:54:24 +08:00
|
|
|
* Copyright (c) 2003-2014 QLogic Corporation
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2005-10-28 02:10:08 +08:00
|
|
|
* See LICENSE.qla2xxx for copyright and licensing details.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
#include "qla_def.h"
|
2012-05-16 02:34:28 +08:00
|
|
|
#include "qla_target.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-21 05:07:37 +08:00
|
|
|
#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 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2017-06-14 11:47:18 +08:00
|
|
|
#include <linux/cpu.h>
|
2016-11-16 03:21:46 +08:00
|
|
|
#include <linux/t10-pi.h>
|
2006-10-14 00:33:39 +08:00
|
|
|
#include <scsi/scsi_tcq.h>
|
2010-01-13 05:02:47 +08:00
|
|
|
#include <scsi/scsi_bsg_fc.h>
|
2010-05-05 06:01:30 +08:00
|
|
|
#include <scsi/scsi_eh.h>
|
2017-08-30 21:12:31 +08:00
|
|
|
#include <scsi/fc/fc_fs.h>
|
|
|
|
#include <linux/nvme-fc-driver.h>
|
2006-10-14 00:33:39 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
|
2008-12-10 08:45:39 +08:00
|
|
|
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
|
2009-04-07 13:33:40 +08:00
|
|
|
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
|
2017-06-14 11:47:16 +08:00
|
|
|
static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
|
2008-12-10 08:45:39 +08:00
|
|
|
sts_entry_t *);
|
2005-07-07 01:31:27 +08:00
|
|
|
|
2019-04-12 05:53:20 +08:00
|
|
|
const char *const port_state_str[] = {
|
|
|
|
"Unknown",
|
|
|
|
"UNCONFIGURED",
|
|
|
|
"DEAD",
|
|
|
|
"LOST",
|
|
|
|
"ONLINE"
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
|
2018-10-19 06:45:41 +08:00
|
|
|
* @irq: interrupt number
|
2005-04-17 06:20:36 +08:00
|
|
|
* @dev_id: SCSI driver HA context
|
|
|
|
*
|
|
|
|
* Called by system whenever the host adapter generates an interrupt.
|
|
|
|
*
|
|
|
|
* Returns handled flag.
|
|
|
|
*/
|
|
|
|
irqreturn_t
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
qla2100_intr_handler(int irq, void *dev_id)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
scsi_qla_host_t *vha;
|
|
|
|
struct qla_hw_data *ha;
|
2005-07-07 01:30:26 +08:00
|
|
|
struct device_reg_2xxx __iomem *reg;
|
2005-04-17 06:20:36 +08:00
|
|
|
int status;
|
|
|
|
unsigned long iter;
|
2007-09-21 05:07:36 +08:00
|
|
|
uint16_t hccr;
|
2019-04-18 05:44:21 +08:00
|
|
|
uint16_t mb[8];
|
2008-11-07 02:40:51 +08:00
|
|
|
struct rsp_que *rsp;
|
2009-06-11 04:55:11 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp = (struct rsp_que *) dev_id;
|
|
|
|
if (!rsp) {
|
2012-02-10 03:15:47 +08:00
|
|
|
ql_log(ql_log_info, NULL, 0x505d,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
2005-04-17 06:20:36 +08:00
|
|
|
return (IRQ_NONE);
|
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha = rsp->hw;
|
2005-07-07 01:30:26 +08:00
|
|
|
reg = &ha->iobase->isp;
|
2005-04-17 06:20:36 +08:00
|
|
|
status = 0;
|
|
|
|
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2009-04-07 13:33:40 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
for (iter = 50; iter--; ) {
|
2007-09-21 05:07:36 +08:00
|
|
|
hccr = RD_REG_WORD(®->hccr);
|
2014-08-27 05:11:41 +08:00
|
|
|
if (qla2x00_check_reg16_for_disconnect(vha, hccr))
|
2013-10-30 15:38:16 +08:00
|
|
|
break;
|
2007-09-21 05:07:36 +08:00
|
|
|
if (hccr & HCCR_RISC_PAUSE) {
|
|
|
|
if (pci_channel_offline(ha->pdev))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Issue a "HARD" reset in order for the RISC interrupt
|
2011-06-24 14:22:27 +08:00
|
|
|
* bit to be cleared. Schedule a big hammer to get
|
2007-09-21 05:07:36 +08:00
|
|
|
* out of the RISC PAUSED state.
|
|
|
|
*/
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
RD_REG_WORD(®->hccr);
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2007-09-21 05:07:36 +08:00
|
|
|
break;
|
|
|
|
} else if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (RD_REG_WORD(®->semaphore) & BIT_0) {
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
|
|
|
RD_REG_WORD(®->hccr);
|
|
|
|
|
|
|
|
/* Get mailbox data. */
|
2005-07-07 01:31:27 +08:00
|
|
|
mb[0] = RD_MAILBOX_REG(ha, reg, 0);
|
|
|
|
if (mb[0] > 0x3fff && mb[0] < 0x8000) {
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_mbx_completion(vha, mb[0]);
|
2005-04-17 06:20:36 +08:00
|
|
|
status |= MBX_INTERRUPT;
|
2005-07-07 01:31:27 +08:00
|
|
|
} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
|
|
|
|
mb[1] = RD_MAILBOX_REG(ha, reg, 1);
|
|
|
|
mb[2] = RD_MAILBOX_REG(ha, reg, 2);
|
|
|
|
mb[3] = RD_MAILBOX_REG(ha, reg, 3);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
|
|
|
/*EMPTY*/
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5025,
|
|
|
|
"Unrecognized interrupt type (%d).\n",
|
|
|
|
mb[0]);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
/* Release mailbox registers. */
|
|
|
|
WRT_REG_WORD(®->semaphore, 0);
|
|
|
|
RD_REG_WORD(®->semaphore);
|
|
|
|
} else {
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_response_queue(rsp);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
|
|
|
RD_REG_WORD(®->hccr);
|
|
|
|
}
|
|
|
|
}
|
2013-04-24 01:13:17 +08:00
|
|
|
qla2x00_handle_mbx_completion(ha, status);
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return (IRQ_HANDLED);
|
|
|
|
}
|
|
|
|
|
2013-10-30 15:38:16 +08:00
|
|
|
bool
|
2014-08-27 05:11:41 +08:00
|
|
|
qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
|
2013-10-30 15:38:16 +08:00
|
|
|
{
|
|
|
|
/* Check for PCI disconnection */
|
2015-04-30 20:13:05 +08:00
|
|
|
if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) {
|
2014-08-27 05:12:14 +08:00
|
|
|
if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
|
2014-08-27 05:12:29 +08:00
|
|
|
!test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
|
|
|
|
!test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
|
2014-08-27 05:12:01 +08:00
|
|
|
/*
|
|
|
|
* Schedule this (only once) on the default system
|
|
|
|
* workqueue so that all the adapter workqueues and the
|
|
|
|
* DPC thread can be shutdown cleanly.
|
|
|
|
*/
|
|
|
|
schedule_work(&vha->hw->board_disable);
|
|
|
|
}
|
2013-10-30 15:38:16 +08:00
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-27 05:11:41 +08:00
|
|
|
bool
|
|
|
|
qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
|
|
|
|
{
|
|
|
|
return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
|
2018-10-19 06:45:41 +08:00
|
|
|
* @irq: interrupt number
|
2005-04-17 06:20:36 +08:00
|
|
|
* @dev_id: SCSI driver HA context
|
|
|
|
*
|
|
|
|
* Called by system whenever the host adapter generates an interrupt.
|
|
|
|
*
|
|
|
|
* Returns handled flag.
|
|
|
|
*/
|
|
|
|
irqreturn_t
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
qla2300_intr_handler(int irq, void *dev_id)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
scsi_qla_host_t *vha;
|
2005-07-07 01:30:26 +08:00
|
|
|
struct device_reg_2xxx __iomem *reg;
|
2005-04-17 06:20:36 +08:00
|
|
|
int status;
|
|
|
|
unsigned long iter;
|
|
|
|
uint32_t stat;
|
|
|
|
uint16_t hccr;
|
2019-04-18 05:44:21 +08:00
|
|
|
uint16_t mb[8];
|
2008-11-07 02:40:51 +08:00
|
|
|
struct rsp_que *rsp;
|
|
|
|
struct qla_hw_data *ha;
|
2009-06-11 04:55:11 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp = (struct rsp_que *) dev_id;
|
|
|
|
if (!rsp) {
|
2012-02-10 03:15:47 +08:00
|
|
|
ql_log(ql_log_info, NULL, 0x5058,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
2005-04-17 06:20:36 +08:00
|
|
|
return (IRQ_NONE);
|
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha = rsp->hw;
|
2005-07-07 01:30:26 +08:00
|
|
|
reg = &ha->iobase->isp;
|
2005-04-17 06:20:36 +08:00
|
|
|
status = 0;
|
|
|
|
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2009-04-07 13:33:40 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
for (iter = 50; iter--; ) {
|
|
|
|
stat = RD_REG_DWORD(®->u.isp2300.host_status);
|
2014-08-27 05:11:41 +08:00
|
|
|
if (qla2x00_check_reg32_for_disconnect(vha, stat))
|
2013-10-30 15:38:16 +08:00
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (stat & HSR_RISC_PAUSED) {
|
2009-12-16 13:29:46 +08:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
2007-09-21 05:07:36 +08:00
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
hccr = RD_REG_WORD(®->hccr);
|
2013-10-30 15:38:16 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5026,
|
|
|
|
"Parity error -- HCCR=%x, Dumping "
|
|
|
|
"firmware.\n", hccr);
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5027,
|
|
|
|
"RISC paused -- HCCR=%x, Dumping "
|
|
|
|
"firmware.\n", hccr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Issue a "HARD" reset in order for the RISC
|
|
|
|
* interrupt bit to be cleared. Schedule a big
|
2011-06-24 14:22:27 +08:00
|
|
|
* hammer to get out of the RISC PAUSED state.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
RD_REG_WORD(®->hccr);
|
2006-12-14 11:20:31 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
} else if ((stat & HSR_RISC_INT) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (stat & 0xff) {
|
|
|
|
case 0x1:
|
|
|
|
case 0x2:
|
|
|
|
case 0x10:
|
|
|
|
case 0x11:
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_mbx_completion(vha, MSW(stat));
|
2005-04-17 06:20:36 +08:00
|
|
|
status |= MBX_INTERRUPT;
|
|
|
|
|
|
|
|
/* Release mailbox registers. */
|
|
|
|
WRT_REG_WORD(®->semaphore, 0);
|
|
|
|
break;
|
|
|
|
case 0x12:
|
2005-07-07 01:31:27 +08:00
|
|
|
mb[0] = MSW(stat);
|
|
|
|
mb[1] = RD_MAILBOX_REG(ha, reg, 1);
|
|
|
|
mb[2] = RD_MAILBOX_REG(ha, reg, 2);
|
|
|
|
mb[3] = RD_MAILBOX_REG(ha, reg, 3);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
|
|
|
case 0x13:
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_response_queue(rsp);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case 0x15:
|
2005-07-07 01:31:27 +08:00
|
|
|
mb[0] = MBA_CMPLT_1_16BIT;
|
|
|
|
mb[1] = MSW(stat);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case 0x16:
|
2005-07-07 01:31:27 +08:00
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
mb[1] = MSW(stat);
|
|
|
|
mb[2] = RD_MAILBOX_REG(ha, reg, 2);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
default:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5028,
|
|
|
|
"Unrecognized interrupt type (%d).\n", stat & 0xff);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
|
|
|
RD_REG_WORD_RELAXED(®->hccr);
|
|
|
|
}
|
2013-04-24 01:13:17 +08:00
|
|
|
qla2x00_handle_mbx_completion(ha, status);
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return (IRQ_HANDLED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_mbx_completion() - Process mailbox command completions.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
2005-04-17 06:20:36 +08:00
|
|
|
* @mb0: Mailbox0 register
|
|
|
|
*/
|
|
|
|
static void
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
uint16_t cnt;
|
2011-11-19 01:03:09 +08:00
|
|
|
uint32_t mboxes;
|
2005-04-17 06:20:36 +08:00
|
|
|
uint16_t __iomem *wptr;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-07 01:30:26 +08:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-11-19 01:03:09 +08:00
|
|
|
/* Read all mbox registers? */
|
2018-01-26 00:24:29 +08:00
|
|
|
WARN_ON_ONCE(ha->mbx_count > 32);
|
|
|
|
mboxes = (1ULL << ha->mbx_count) - 1;
|
2011-11-19 01:03:09 +08:00
|
|
|
if (!ha->mcp)
|
2012-11-21 15:40:42 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
|
2011-11-19 01:03:09 +08:00
|
|
|
else
|
|
|
|
mboxes = ha->mcp->in_mb;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Load return mailbox registers. */
|
|
|
|
ha->flags.mbox_int = 1;
|
|
|
|
ha->mailbox_out[0] = mb0;
|
2011-11-19 01:03:09 +08:00
|
|
|
mboxes >>= 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);
|
|
|
|
|
|
|
|
for (cnt = 1; cnt < ha->mbx_count; cnt++) {
|
2005-07-07 01:32:07 +08:00
|
|
|
if (IS_QLA2200(ha) && cnt == 8)
|
2005-04-17 06:20:36 +08:00
|
|
|
wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
|
2011-11-19 01:03:09 +08:00
|
|
|
if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
|
2005-04-17 06:20:36 +08:00
|
|
|
ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
|
2011-11-19 01:03:09 +08:00
|
|
|
else if (mboxes & BIT_0)
|
2005-04-17 06:20:36 +08:00
|
|
|
ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
|
2005-07-07 01:32:07 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
wptr++;
|
2011-11-19 01:03:09 +08:00
|
|
|
mboxes >>= 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-09 12:50:12 +08:00
|
|
|
static void
|
|
|
|
qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
|
|
|
|
{
|
|
|
|
static char *event[] =
|
|
|
|
{ "Complete", "Request Notification", "Time Extension" };
|
|
|
|
int rval;
|
|
|
|
struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
|
2013-10-30 15:38:23 +08:00
|
|
|
struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
|
2009-02-09 12:50:12 +08:00
|
|
|
uint16_t __iomem *wptr;
|
|
|
|
uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
|
|
|
|
|
|
|
|
/* Seed data -- mailbox1 -> mailbox7. */
|
2013-10-30 15:38:23 +08:00
|
|
|
if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
|
|
|
|
wptr = (uint16_t __iomem *)®24->mailbox1;
|
|
|
|
else if (IS_QLA8044(vha->hw))
|
|
|
|
wptr = (uint16_t __iomem *)®82->mailbox_out[1];
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
2009-02-09 12:50:12 +08:00
|
|
|
for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
|
|
|
|
mb[cnt] = RD_REG_WORD(wptr);
|
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5021,
|
2012-02-10 03:15:34 +08:00
|
|
|
"Inter-Driver Communication %s -- "
|
2011-07-15 03:00:13 +08:00
|
|
|
"%04x %04x %04x %04x %04x %04x %04x.\n",
|
|
|
|
event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
|
|
|
|
mb[4], mb[5], mb[6]);
|
2013-08-27 13:37:48 +08:00
|
|
|
switch (aen) {
|
|
|
|
/* Handle IDC Error completion case. */
|
|
|
|
case MBA_IDC_COMPLETE:
|
|
|
|
if (mb[1] >> 15) {
|
|
|
|
vha->hw->flags.idc_compl_status = 1;
|
2013-10-30 15:38:25 +08:00
|
|
|
if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
|
2013-08-27 13:37:48 +08:00
|
|
|
complete(&vha->hw->dcbx_comp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_IDC_NOTIFY:
|
|
|
|
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
|
|
|
timeout = (descr >> 8) & 0xf;
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5022,
|
|
|
|
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
|
|
|
|
vha->host_no, event[aen & 0xff], timeout);
|
|
|
|
|
|
|
|
if (!timeout)
|
|
|
|
return;
|
|
|
|
rval = qla2x00_post_idc_ack_work(vha, mb);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
ql_log(ql_log_warn, vha, 0x5023,
|
|
|
|
"IDC failed to post ACK.\n");
|
|
|
|
break;
|
|
|
|
case MBA_IDC_TIME_EXT:
|
|
|
|
vha->hw->idc_extend_tmo = descr;
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5087,
|
|
|
|
"%lu Inter-Driver Communication %s -- "
|
|
|
|
"Extend timeout by=%d.\n",
|
|
|
|
vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
|
|
|
|
break;
|
2012-08-23 02:21:24 +08:00
|
|
|
}
|
2009-02-09 12:50:12 +08:00
|
|
|
}
|
|
|
|
|
2012-05-16 02:34:23 +08:00
|
|
|
#define LS_UNKNOWN 2
|
2012-11-21 15:40:40 +08:00
|
|
|
const char *
|
|
|
|
qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
|
2012-05-16 02:34:23 +08:00
|
|
|
{
|
2014-02-26 17:15:06 +08:00
|
|
|
static const char *const link_speeds[] = {
|
|
|
|
"1", "2", "?", "4", "8", "16", "32", "10"
|
2012-11-21 15:40:40 +08:00
|
|
|
};
|
2019-04-05 03:44:41 +08:00
|
|
|
#define QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
|
2012-05-16 02:34:23 +08:00
|
|
|
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha))
|
2012-11-21 15:40:40 +08:00
|
|
|
return link_speeds[0];
|
|
|
|
else if (speed == 0x13)
|
2014-02-26 17:15:06 +08:00
|
|
|
return link_speeds[QLA_LAST_SPEED];
|
|
|
|
else if (speed < QLA_LAST_SPEED)
|
2012-11-21 15:40:40 +08:00
|
|
|
return link_speeds[speed];
|
|
|
|
else
|
|
|
|
return link_speeds[LS_UNKNOWN];
|
2012-05-16 02:34:23 +08:00
|
|
|
}
|
|
|
|
|
2012-11-21 15:40:29 +08:00
|
|
|
static void
|
2012-08-23 02:21:03 +08:00
|
|
|
qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 8200 AEN Interpretation:
|
|
|
|
* mb[0] = AEN code
|
|
|
|
* mb[1] = AEN Reason code
|
|
|
|
* mb[2] = LSW of Peg-Halt Status-1 Register
|
|
|
|
* mb[6] = MSW of Peg-Halt Status-1 Register
|
|
|
|
* mb[3] = LSW of Peg-Halt Status-2 register
|
|
|
|
* mb[7] = MSW of Peg-Halt Status-2 register
|
|
|
|
* mb[4] = IDC Device-State Register value
|
|
|
|
* mb[5] = IDC Driver-Presence Register value
|
|
|
|
*/
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
|
|
|
|
"mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
|
|
|
|
mb[0], mb[1], mb[2], mb[6]);
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
|
|
|
|
"PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
|
|
|
|
"Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
|
|
|
|
|
|
|
|
if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
|
|
|
|
IDC_HEARTBEAT_FAILURE)) {
|
|
|
|
ha->flags.nic_core_hung = 1;
|
|
|
|
ql_log(ql_log_warn, vha, 0x5060,
|
|
|
|
"83XX: F/W Error Reported: Check if reset required.\n");
|
|
|
|
|
|
|
|
if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
|
|
|
|
uint32_t protocol_engine_id, fw_err_code, err_level;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IDC_PEG_HALT_STATUS_CHANGE interpretation:
|
|
|
|
* - PEG-Halt Status-1 Register:
|
|
|
|
* (LSW = mb[2], MSW = mb[6])
|
|
|
|
* Bits 0-7 = protocol-engine ID
|
|
|
|
* Bits 8-28 = f/w error code
|
|
|
|
* Bits 29-31 = Error-level
|
|
|
|
* Error-level 0x1 = Non-Fatal error
|
|
|
|
* Error-level 0x2 = Recoverable Fatal error
|
|
|
|
* Error-level 0x4 = UnRecoverable Fatal error
|
|
|
|
* - PEG-Halt Status-2 Register:
|
|
|
|
* (LSW = mb[3], MSW = mb[7])
|
|
|
|
*/
|
|
|
|
protocol_engine_id = (mb[2] & 0xff);
|
|
|
|
fw_err_code = (((mb[2] & 0xff00) >> 8) |
|
|
|
|
((mb[6] & 0x1fff) << 8));
|
|
|
|
err_level = ((mb[6] & 0xe000) >> 13);
|
|
|
|
ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
|
|
|
|
"Register: protocol_engine_id=0x%x "
|
|
|
|
"fw_err_code=0x%x err_level=0x%x.\n",
|
|
|
|
protocol_engine_id, fw_err_code, err_level);
|
|
|
|
ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
|
|
|
|
"Register: 0x%x%x.\n", mb[7], mb[3]);
|
|
|
|
if (err_level == ERR_LEVEL_NON_FATAL) {
|
|
|
|
ql_log(ql_log_warn, vha, 0x5063,
|
2017-06-30 21:47:41 +08:00
|
|
|
"Not a fatal error, f/w has recovered itself.\n");
|
2012-08-23 02:21:03 +08:00
|
|
|
} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
|
|
|
|
ql_log(ql_log_fatal, vha, 0x5064,
|
|
|
|
"Recoverable Fatal error: Chip reset "
|
|
|
|
"required.\n");
|
|
|
|
qla83xx_schedule_work(vha,
|
|
|
|
QLA83XX_NIC_CORE_RESET);
|
|
|
|
} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
|
|
|
|
ql_log(ql_log_fatal, vha, 0x5065,
|
|
|
|
"Unrecoverable Fatal error: Set FAILED "
|
|
|
|
"state, reboot required.\n");
|
|
|
|
qla83xx_schedule_work(vha,
|
|
|
|
QLA83XX_NIC_CORE_UNRECOVERABLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
|
|
|
|
uint16_t peg_fw_state, nw_interface_link_up;
|
|
|
|
uint16_t nw_interface_signal_detect, sfp_status;
|
|
|
|
uint16_t htbt_counter, htbt_monitor_enable;
|
2017-08-16 16:51:20 +08:00
|
|
|
uint16_t sfp_additional_info, sfp_multirate;
|
2012-08-23 02:21:03 +08:00
|
|
|
uint16_t sfp_tx_fault, link_speed, dcbx_status;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IDC_NIC_FW_REPORTED_FAILURE interpretation:
|
|
|
|
* - PEG-to-FC Status Register:
|
|
|
|
* (LSW = mb[2], MSW = mb[6])
|
|
|
|
* Bits 0-7 = Peg-Firmware state
|
|
|
|
* Bit 8 = N/W Interface Link-up
|
|
|
|
* Bit 9 = N/W Interface signal detected
|
|
|
|
* Bits 10-11 = SFP Status
|
|
|
|
* SFP Status 0x0 = SFP+ transceiver not expected
|
|
|
|
* SFP Status 0x1 = SFP+ transceiver not present
|
|
|
|
* SFP Status 0x2 = SFP+ transceiver invalid
|
|
|
|
* SFP Status 0x3 = SFP+ transceiver present and
|
|
|
|
* valid
|
|
|
|
* Bits 12-14 = Heartbeat Counter
|
|
|
|
* Bit 15 = Heartbeat Monitor Enable
|
|
|
|
* Bits 16-17 = SFP Additional Info
|
|
|
|
* SFP info 0x0 = Unregocnized transceiver for
|
|
|
|
* Ethernet
|
|
|
|
* SFP info 0x1 = SFP+ brand validation failed
|
|
|
|
* SFP info 0x2 = SFP+ speed validation failed
|
|
|
|
* SFP info 0x3 = SFP+ access error
|
|
|
|
* Bit 18 = SFP Multirate
|
|
|
|
* Bit 19 = SFP Tx Fault
|
|
|
|
* Bits 20-22 = Link Speed
|
|
|
|
* Bits 23-27 = Reserved
|
|
|
|
* Bits 28-30 = DCBX Status
|
|
|
|
* DCBX Status 0x0 = DCBX Disabled
|
|
|
|
* DCBX Status 0x1 = DCBX Enabled
|
|
|
|
* DCBX Status 0x2 = DCBX Exchange error
|
|
|
|
* Bit 31 = Reserved
|
|
|
|
*/
|
|
|
|
peg_fw_state = (mb[2] & 0x00ff);
|
|
|
|
nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
|
|
|
|
nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
|
|
|
|
sfp_status = ((mb[2] & 0x0c00) >> 10);
|
|
|
|
htbt_counter = ((mb[2] & 0x7000) >> 12);
|
|
|
|
htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
|
2017-08-16 16:51:20 +08:00
|
|
|
sfp_additional_info = (mb[6] & 0x0003);
|
2012-08-23 02:21:03 +08:00
|
|
|
sfp_multirate = ((mb[6] & 0x0004) >> 2);
|
|
|
|
sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
|
|
|
|
link_speed = ((mb[6] & 0x0070) >> 4);
|
|
|
|
dcbx_status = ((mb[6] & 0x7000) >> 12);
|
|
|
|
|
|
|
|
ql_log(ql_log_warn, vha, 0x5066,
|
|
|
|
"Peg-to-Fc Status Register:\n"
|
|
|
|
"peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
|
|
|
|
"nw_interface_signal_detect=0x%x"
|
|
|
|
"\nsfp_statis=0x%x.\n ", peg_fw_state,
|
|
|
|
nw_interface_link_up, nw_interface_signal_detect,
|
|
|
|
sfp_status);
|
|
|
|
ql_log(ql_log_warn, vha, 0x5067,
|
|
|
|
"htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
|
2017-08-16 16:51:20 +08:00
|
|
|
"sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ",
|
2012-08-23 02:21:03 +08:00
|
|
|
htbt_counter, htbt_monitor_enable,
|
2017-08-16 16:51:20 +08:00
|
|
|
sfp_additional_info, sfp_multirate);
|
2012-08-23 02:21:03 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5068,
|
|
|
|
"sfp_tx_fault=0x%x, link_state=0x%x, "
|
|
|
|
"dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
|
|
|
|
dcbx_status);
|
|
|
|
|
|
|
|
qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mb[1] & IDC_HEARTBEAT_FAILURE) {
|
|
|
|
ql_log(ql_log_warn, vha, 0x5069,
|
|
|
|
"Heartbeat Failure encountered, chip reset "
|
|
|
|
"required.\n");
|
|
|
|
|
|
|
|
qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
|
|
|
|
ql_log(ql_log_info, vha, 0x506a,
|
|
|
|
"IDC Device-State changed = 0x%x.\n", mb[4]);
|
2013-02-08 14:58:02 +08:00
|
|
|
if (ha->flags.nic_core_reset_owner)
|
|
|
|
return;
|
2012-08-23 02:21:03 +08:00
|
|
|
qla83xx_schedule_work(vha, MBA_IDC_AEN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-08 14:58:01 +08:00
|
|
|
int
|
|
|
|
qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
scsi_qla_host_t *vp;
|
|
|
|
uint32_t vp_did;
|
|
|
|
unsigned long flags;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!ha->num_vhosts)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->vport_slock, flags);
|
|
|
|
list_for_each_entry(vp, &ha->vp_list, list) {
|
|
|
|
vp_did = vp->d_id.b24;
|
|
|
|
if (vp_did == rscn_entry) {
|
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
fc_port_t *
|
2015-08-05 01:37:52 +08:00
|
|
|
qla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id)
|
|
|
|
{
|
2017-01-20 14:28:00 +08:00
|
|
|
fc_port_t *f, *tf;
|
|
|
|
|
|
|
|
f = tf = NULL;
|
|
|
|
list_for_each_entry_safe(f, tf, &vha->vp_fcports, list)
|
|
|
|
if (f->loop_id == loop_id)
|
|
|
|
return f;
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-05 01:37:52 +08:00
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
fc_port_t *
|
|
|
|
qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *vha, u8 *wwpn, u8 incl_deleted)
|
|
|
|
{
|
|
|
|
fc_port_t *f, *tf;
|
|
|
|
|
|
|
|
f = tf = NULL;
|
|
|
|
list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
|
|
|
|
if (memcmp(f->port_name, wwpn, WWN_SIZE) == 0) {
|
|
|
|
if (incl_deleted)
|
|
|
|
return f;
|
|
|
|
else if (f->deleted == 0)
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-05 01:37:52 +08:00
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
fc_port_t *
|
|
|
|
qla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id,
|
|
|
|
u8 incl_deleted)
|
|
|
|
{
|
|
|
|
fc_port_t *f, *tf;
|
|
|
|
|
|
|
|
f = tf = NULL;
|
|
|
|
list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
|
|
|
|
if (f->d_id.b24 == id->b24) {
|
|
|
|
if (incl_deleted)
|
|
|
|
return f;
|
|
|
|
else if (f->deleted == 0)
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
2015-08-05 01:37:52 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2x00_async_event() - Process aynchronous events.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
|
|
|
* @rsp: response queue
|
2005-07-07 01:31:27 +08:00
|
|
|
* @mb: Mailbox registers (0 - 3)
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2007-07-06 04:16:51 +08:00
|
|
|
void
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
uint16_t handle_cnt;
|
2009-10-14 06:16:46 +08:00
|
|
|
uint16_t cnt, mbx;
|
2005-04-17 06:20:36 +08:00
|
|
|
uint32_t handles[5];
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-07 01:30:26 +08:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2009-10-14 06:16:46 +08:00
|
|
|
struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
|
2010-12-22 08:00:24 +08:00
|
|
|
struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
|
2015-07-09 22:23:26 +08:00
|
|
|
uint32_t rscn_entry, host_pid;
|
2008-04-04 04:13:26 +08:00
|
|
|
unsigned long flags;
|
2014-09-25 17:17:01 +08:00
|
|
|
fc_port_t *fcport = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-07-19 05:29:53 +08:00
|
|
|
if (!vha->hw->flags.fw_started)
|
|
|
|
return;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Setup to process RIO completion. */
|
|
|
|
handle_cnt = 0;
|
2012-02-10 03:15:34 +08:00
|
|
|
if (IS_CNA_CAPABLE(ha))
|
2009-01-06 03:18:11 +08:00
|
|
|
goto skip_rio;
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (mb[0]) {
|
|
|
|
case MBA_SCSI_COMPLETION:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
|
2005-04-17 06:20:36 +08:00
|
|
|
handle_cnt = 1;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_1_16BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = mb[1];
|
2005-04-17 06:20:36 +08:00
|
|
|
handle_cnt = 1;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_2_16BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = mb[1];
|
|
|
|
handles[1] = mb[2];
|
2005-04-17 06:20:36 +08:00
|
|
|
handle_cnt = 2;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_3_16BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = mb[1];
|
|
|
|
handles[1] = mb[2];
|
|
|
|
handles[2] = mb[3];
|
2005-04-17 06:20:36 +08:00
|
|
|
handle_cnt = 3;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_4_16BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = mb[1];
|
|
|
|
handles[1] = mb[2];
|
|
|
|
handles[2] = mb[3];
|
2005-04-17 06:20:36 +08:00
|
|
|
handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
|
|
|
|
handle_cnt = 4;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_5_16BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = mb[1];
|
|
|
|
handles[1] = mb[2];
|
|
|
|
handles[2] = mb[3];
|
2005-04-17 06:20:36 +08:00
|
|
|
handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
|
|
|
|
handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
|
|
|
|
handle_cnt = 5;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
case MBA_CMPLT_2_32BIT:
|
2005-07-07 01:31:27 +08:00
|
|
|
handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
|
2005-04-17 06:20:36 +08:00
|
|
|
handles[1] = le32_to_cpu(
|
|
|
|
((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
|
|
|
|
RD_MAILBOX_REG(ha, reg, 6));
|
|
|
|
handle_cnt = 2;
|
|
|
|
mb[0] = MBA_SCSI_COMPLETION;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2009-01-06 03:18:11 +08:00
|
|
|
skip_rio:
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (mb[0]) {
|
|
|
|
case MBA_SCSI_COMPLETION: /* Fast Post */
|
2008-11-07 02:40:51 +08:00
|
|
|
if (!vha->flags.online)
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
for (cnt = 0; cnt < handle_cnt; cnt++)
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_completed_request(vha, rsp->req,
|
|
|
|
handles[cnt]);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_RESET: /* Reset */
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5002,
|
|
|
|
"Asynchronous RESET.\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_SYSTEM_ERR: /* System Error */
|
2019-03-13 02:08:13 +08:00
|
|
|
mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
|
|
|
|
IS_QLA28XX(ha)) ?
|
2012-02-10 03:15:34 +08:00
|
|
|
RD_REG_WORD(®24->mailbox7) : 0;
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5003,
|
2009-10-14 06:16:46 +08:00
|
|
|
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
|
|
|
|
"mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
|
2019-03-13 02:08:14 +08:00
|
|
|
ha->fw_dump_mpi =
|
|
|
|
(IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
|
|
|
|
RD_REG_WORD(®24->mailbox7) & BIT_8;
|
2008-11-07 02:40:51 +08:00
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
2017-03-16 00:48:55 +08:00
|
|
|
ha->flags.fw_init_done = 0;
|
2017-06-14 11:47:21 +08:00
|
|
|
QLA_FW_STOPPED(ha);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-20 06:05:56 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
2005-07-07 01:31:27 +08:00
|
|
|
if (mb[1] == 0 && mb[2] == 0) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_fatal, vha, 0x5004,
|
2005-07-07 01:31:27 +08:00
|
|
|
"Unrecoverable Hardware Error: adapter "
|
|
|
|
"marked OFFLINE!\n");
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.online = 0;
|
2012-02-10 03:15:34 +08:00
|
|
|
vha->device_flags |= DFLG_DEV_FAILED;
|
2010-09-04 06:20:54 +08:00
|
|
|
} else {
|
2011-03-31 09:57:33 +08:00
|
|
|
/* Check to see if MPI timeout occurred */
|
2014-02-26 17:15:06 +08:00
|
|
|
if ((mbx & MBX_3) && (ha->port_no == 0))
|
2010-09-04 06:20:54 +08:00
|
|
|
set_bit(MPI_RESET_NEEDED,
|
|
|
|
&vha->dpc_flags);
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2010-09-04 06:20:54 +08:00
|
|
|
}
|
2005-07-07 01:31:27 +08:00
|
|
|
} else if (mb[1] == 0) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_fatal, vha, 0x5005,
|
2005-04-17 06:20:36 +08:00
|
|
|
"Unrecoverable Hardware Error: adapter marked "
|
|
|
|
"OFFLINE!\n");
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.online = 0;
|
2012-02-10 03:15:34 +08:00
|
|
|
vha->device_flags |= DFLG_DEV_FAILED;
|
2005-04-17 06:20:36 +08:00
|
|
|
} else
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5006,
|
|
|
|
"ISP Request Transfer Error (%x).\n", mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5007,
|
2016-07-06 23:14:29 +08:00
|
|
|
"ISP Response Transfer Error (%x).\n", mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5008,
|
2016-07-06 23:14:29 +08:00
|
|
|
"Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-07-06 23:14:29 +08:00
|
|
|
case MBA_LOOP_INIT_ERR:
|
2016-07-06 23:14:33 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5090,
|
2016-07-06 23:14:29 +08:00
|
|
|
"LOOP INIT ERROR (%x).\n", mb[1]);
|
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2012-05-16 02:34:28 +08:00
|
|
|
break;
|
2016-07-06 23:14:29 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
|
2017-03-16 00:48:55 +08:00
|
|
|
ha->flags.lip_ae = 1;
|
|
|
|
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5009,
|
2011-07-15 03:00:13 +08:00
|
|
|
"LIP occurred (%x).\n", mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
|
2007-07-06 04:16:51 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
|
|
|
qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_LOOP_UP: /* Loop Up Event */
|
2012-05-16 02:34:23 +08:00
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha))
|
2006-10-03 03:00:43 +08:00
|
|
|
ha->link_data_rate = PORT_SPEED_1GB;
|
2012-05-16 02:34:23 +08:00
|
|
|
else
|
2005-04-17 06:20:36 +08:00
|
|
|
ha->link_data_rate = mb[1];
|
|
|
|
|
2014-08-08 19:38:09 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x500a,
|
2012-05-16 02:34:23 +08:00
|
|
|
"LOOP UP detected (%s Gbps).\n",
|
2012-11-21 15:40:40 +08:00
|
|
|
qla2x00_get_link_speed_str(ha, ha->link_data_rate));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
|
|
|
qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
|
2017-08-24 06:05:07 +08:00
|
|
|
|
|
|
|
if (AUTO_DETECT_SFP_SUPPORT(vha)) {
|
|
|
|
set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
|
|
|
|
qla2xxx_wake_dpc(vha);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_LOOP_DOWN: /* Loop Down Event */
|
2017-12-29 04:33:24 +08:00
|
|
|
SAVE_TOPO(ha);
|
2017-03-16 00:48:55 +08:00
|
|
|
ha->flags.lip_ae = 0;
|
|
|
|
ha->current_topology = 0;
|
|
|
|
|
2012-02-10 03:15:34 +08:00
|
|
|
mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
|
|
|
|
? RD_REG_WORD(®24->mailbox4) : 0;
|
2013-08-27 13:37:28 +08:00
|
|
|
mbx = (IS_P3P_TYPE(ha)) ? RD_REG_WORD(®82->mailbox_out[4])
|
|
|
|
: mbx;
|
2014-08-08 19:38:09 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x500b,
|
2011-07-15 03:00:13 +08:00
|
|
|
"LOOP DOWN detected (%x %x %x %x).\n",
|
|
|
|
mb[1], mb[2], mb[3], mbx);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
2014-09-25 17:17:00 +08:00
|
|
|
/*
|
|
|
|
* In case of loop down, restore WWPN from
|
|
|
|
* NVRAM in case of FA-WWPN capable ISP
|
2015-04-10 03:00:07 +08:00
|
|
|
* Restore for Physical Port only
|
2014-09-25 17:17:00 +08:00
|
|
|
*/
|
2015-04-10 03:00:07 +08:00
|
|
|
if (!vha->vp_idx) {
|
2019-01-25 15:23:48 +08:00
|
|
|
if (ha->flags.fawwpn_enabled &&
|
|
|
|
(ha->current_topology == ISP_CFG_F)) {
|
2015-04-10 03:00:07 +08:00
|
|
|
void *wwpn = ha->init_cb->port_name;
|
2019-04-12 05:53:17 +08:00
|
|
|
|
2015-04-10 03:00:07 +08:00
|
|
|
memcpy(vha->port_name, wwpn, WWN_SIZE);
|
|
|
|
fc_host_port_name(vha->host) =
|
|
|
|
wwn_to_u64(vha->port_name);
|
|
|
|
ql_dbg(ql_dbg_init + ql_dbg_verbose,
|
2017-06-03 00:12:01 +08:00
|
|
|
vha, 0x00d8, "LOOP DOWN detected,"
|
2015-04-10 03:00:07 +08:00
|
|
|
"restore WWPN %016llx\n",
|
|
|
|
wwn_to_u64(vha->port_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
clear_bit(VP_CONFIG_OK, &vha->vp_flags);
|
2014-09-25 17:17:00 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->device_flags |= DFLG_NO_CABLE;
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
|
2007-07-06 04:16:51 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
2006-10-03 03:00:43 +08:00
|
|
|
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_LIP_RESET: /* LIP reset occurred */
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x500c,
|
2008-09-12 12:22:51 +08:00
|
|
|
"LIP reset occurred (%x).\n", mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
|
2007-07-06 04:16:51 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
ha->operating_mode = LOOP;
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
|
|
|
qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2009-01-06 03:18:11 +08:00
|
|
|
/* case MBA_DCBX_COMPLETE: */
|
2005-04-17 06:20:36 +08:00
|
|
|
case MBA_POINT_TO_POINT: /* Point-to-Point */
|
2017-03-16 00:48:55 +08:00
|
|
|
ha->flags.lip_ae = 0;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (IS_QLA2100(ha))
|
|
|
|
break;
|
|
|
|
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_CNA_CAPABLE(ha)) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x500d,
|
|
|
|
"DCBX Completed -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2013-10-30 15:38:25 +08:00
|
|
|
if (ha->notify_dcbx_comp && !vha->vp_idx)
|
2010-05-29 06:08:21 +08:00
|
|
|
complete(&ha->dcbx_comp);
|
|
|
|
|
|
|
|
} else
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x500e,
|
|
|
|
"Asynchronous P2P MODE received.\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Until there's a transition from loop down to loop up, treat
|
|
|
|
* this as loop down only.
|
|
|
|
*/
|
2008-11-07 02:40:51 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
if (!atomic_read(&vha->loop_down_timer))
|
|
|
|
atomic_set(&vha->loop_down_timer,
|
2005-04-17 06:20:36 +08:00
|
|
|
LOOP_DOWN_TIME);
|
2018-08-03 04:16:44 +08:00
|
|
|
if (!N2N_TOPO(ha))
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
|
2007-07-06 04:16:51 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
|
|
|
|
set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
|
|
|
|
|
|
|
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
|
2006-12-14 11:20:28 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_CHG_IN_CONNECTION: /* Change in connection mode */
|
|
|
|
if (IS_QLA2100(ha))
|
|
|
|
break;
|
|
|
|
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x500f,
|
2005-04-17 06:20:36 +08:00
|
|
|
"Configuration change detected: value=%x.\n", mb[1]);
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
if (!atomic_read(&vha->loop_down_timer))
|
|
|
|
atomic_set(&vha->loop_down_timer,
|
2005-04-17 06:20:36 +08:00
|
|
|
LOOP_DOWN_TIME);
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
|
2007-07-06 04:16:51 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_PORT_UPDATE: /* Port database update */
|
2009-08-01 06:09:25 +08:00
|
|
|
/*
|
|
|
|
* Handle only global and vn-port update events
|
|
|
|
*
|
|
|
|
* Relevant inputs:
|
|
|
|
* mb[1] = N_Port handle of changed port
|
|
|
|
* OR 0xffff for global event
|
|
|
|
* mb[2] = New login state
|
|
|
|
* 7 = Port logged out
|
|
|
|
* mb[3] = LSB is vp_idx, 0xff = all vps
|
|
|
|
*
|
|
|
|
* Skip processing if:
|
|
|
|
* Event is global, vp_idx is NOT all vps,
|
|
|
|
* vp_idx does not match
|
|
|
|
* Event is not global, vp_idx does not match
|
|
|
|
*/
|
2010-03-20 07:59:17 +08:00
|
|
|
if (IS_QLA2XXX_MIDTYPE(ha) &&
|
|
|
|
((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
|
|
|
|
(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
|
|
|
|
break;
|
2008-12-10 08:45:39 +08:00
|
|
|
|
2015-08-05 01:37:52 +08:00
|
|
|
if (mb[2] == 0x7) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5010,
|
2015-08-05 01:37:52 +08:00
|
|
|
"Port %s %04x %04x %04x.\n",
|
|
|
|
mb[1] == 0xffff ? "unavailable" : "logout",
|
2011-07-15 03:00:13 +08:00
|
|
|
mb[1], mb[2], mb[3]);
|
2015-08-05 01:37:52 +08:00
|
|
|
|
|
|
|
if (mb[1] == 0xffff)
|
|
|
|
goto global_port_update;
|
|
|
|
|
2017-06-03 00:12:00 +08:00
|
|
|
if (mb[1] == NPH_SNS_LID(ha)) {
|
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* use handle_cnt for loop id/nport handle */
|
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
|
|
|
handle_cnt = NPH_SNS;
|
|
|
|
else
|
|
|
|
handle_cnt = SIMPLE_NAME_SERVER;
|
|
|
|
if (mb[1] == handle_cnt) {
|
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-05 01:37:52 +08:00
|
|
|
/* Port logout */
|
|
|
|
fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
|
|
|
|
if (!fcport)
|
|
|
|
break;
|
|
|
|
if (atomic_read(&fcport->state) != FCS_ONLINE)
|
|
|
|
break;
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x508a,
|
|
|
|
"Marking port lost loopid=%04x portid=%06x.\n",
|
|
|
|
fcport->loop_id, fcport->d_id.b24);
|
2017-01-20 14:28:00 +08:00
|
|
|
if (qla_ini_mode_enabled(vha)) {
|
|
|
|
qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
|
|
|
|
fcport->logout_on_delete = 0;
|
2017-12-29 04:33:43 +08:00
|
|
|
qlt_schedule_sess_for_deletion(fcport);
|
2017-01-20 14:28:00 +08:00
|
|
|
}
|
2015-08-05 01:37:52 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
global_port_update:
|
2009-08-01 06:09:24 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
atomic_set(&vha->loop_down_timer,
|
|
|
|
LOOP_DOWN_TIME);
|
|
|
|
vha->device_flags |= DFLG_NO_CABLE;
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vha->vp_idx) {
|
|
|
|
atomic_set(&vha->vp_state, VP_FAILED);
|
|
|
|
fc_vport_set_state(vha->fc_vport,
|
|
|
|
FC_VPORT_FAILED);
|
2009-08-01 06:09:26 +08:00
|
|
|
qla2x00_mark_all_devices_lost(vha, 1);
|
2009-08-01 06:09:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
vha->flags.management_server_logged_in = 0;
|
|
|
|
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2008-09-12 12:22:51 +08:00
|
|
|
* If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
|
2005-04-17 06:20:36 +08:00
|
|
|
* event etc. earlier indicating loop is down) then process
|
|
|
|
* it. Otherwise ignore it and Wait for RSCN to come in.
|
|
|
|
*/
|
2008-11-07 02:40:51 +08:00
|
|
|
atomic_set(&vha->loop_down_timer, 0);
|
2014-08-08 19:38:09 +08:00
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
|
2017-10-14 00:34:06 +08:00
|
|
|
!ha->flags.n2n_ae &&
|
2014-08-08 19:38:09 +08:00
|
|
|
atomic_read(&vha->loop_state) != LOOP_DEAD) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5011,
|
|
|
|
"Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2012-05-16 02:34:28 +08:00
|
|
|
|
|
|
|
qlt_async_event(mb[0], vha, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5012,
|
|
|
|
"Port database changed %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark all devices as missing so we will login again.
|
|
|
|
*/
|
2008-11-07 02:40:51 +08:00
|
|
|
atomic_set(&vha->loop_state, LOOP_UP);
|
2017-12-29 04:33:39 +08:00
|
|
|
vha->scan.scan_retry = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
2015-04-10 03:00:06 +08:00
|
|
|
set_bit(VP_CONFIG_OK, &vha->vp_flags);
|
2012-05-16 02:34:28 +08:00
|
|
|
|
|
|
|
qlt_async_event(mb[0], vha, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_RSCN_UPDATE: /* State Change Registration */
|
2008-05-20 05:25:39 +08:00
|
|
|
/* Check if the Vport has issued a SCR */
|
2008-11-07 02:40:51 +08:00
|
|
|
if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
|
2008-05-20 05:25:39 +08:00
|
|
|
break;
|
|
|
|
/* Only handle SCNs for our Vport index. */
|
2009-08-26 02:36:19 +08:00
|
|
|
if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
|
2008-05-20 05:25:39 +08:00
|
|
|
break;
|
2009-08-26 02:36:19 +08:00
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5013,
|
|
|
|
"RSCN database changed -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-09-12 12:22:53 +08:00
|
|
|
rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
|
2008-11-07 02:40:51 +08:00
|
|
|
host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
|
|
|
|
| vha->d_id.b.al_pa;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rscn_entry == host_pid) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5014,
|
|
|
|
"Ignoring RSCN update to local host "
|
|
|
|
"port ID (%06x).\n", host_pid);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-09-12 12:22:53 +08:00
|
|
|
/* Ignore reserved bits from RSCN-payload. */
|
|
|
|
rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-02-08 14:58:01 +08:00
|
|
|
/* Skip RSCNs for virtual ports on the same physical port */
|
|
|
|
if (qla2x00_is_a_vp_did(vha, rscn_entry))
|
|
|
|
break;
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
atomic_set(&vha->loop_down_timer, 0);
|
|
|
|
vha->flags.management_server_logged_in = 0;
|
2017-01-20 14:28:00 +08:00
|
|
|
{
|
|
|
|
struct event_arg ea;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
memset(&ea, 0, sizeof(ea));
|
|
|
|
ea.event = FCME_RSCN;
|
|
|
|
ea.id.b24 = rscn_entry;
|
2017-01-20 14:28:03 +08:00
|
|
|
ea.id.b.rsvd_1 = rscn_entry >> 24;
|
2017-01-20 14:28:00 +08:00
|
|
|
qla2x00_fcport_event_handler(vha, &ea);
|
2017-01-20 14:28:03 +08:00
|
|
|
qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
|
2017-01-20 14:28:00 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
/* case MBA_RIO_RESPONSE: */
|
|
|
|
case MBA_ZIO_RESPONSE:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5015,
|
|
|
|
"[R|Z]IO update completion.\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-20 06:05:56 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
2009-04-07 13:33:40 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
2005-10-28 02:09:48 +08:00
|
|
|
else
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_response_queue(rsp);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2005-07-07 01:31:27 +08:00
|
|
|
|
|
|
|
case MBA_DISCARD_RND_FRAME:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5016,
|
|
|
|
"Discard RND Frame -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
2006-08-02 04:48:14 +08:00
|
|
|
|
|
|
|
case MBA_TRACE_NOTIFICATION:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5017,
|
|
|
|
"Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
|
2006-08-02 04:48:14 +08:00
|
|
|
break;
|
2008-04-04 04:13:26 +08:00
|
|
|
|
|
|
|
case MBA_ISP84XX_ALERT:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5018,
|
|
|
|
"ISP84XX Alert Notification -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2008-04-04 04:13:26 +08:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
|
|
|
|
switch (mb[1]) {
|
|
|
|
case A84_PANIC_RECOVERY:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x5019,
|
|
|
|
"Alert 84XX: panic recovery %04x %04x.\n",
|
|
|
|
mb[2], mb[3]);
|
2008-04-04 04:13:26 +08:00
|
|
|
break;
|
|
|
|
case A84_OP_LOGIN_COMPLETE:
|
|
|
|
ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x501a,
|
|
|
|
"Alert 84XX: firmware version %x.\n",
|
|
|
|
ha->cs84xx->op_fw_version);
|
2008-04-04 04:13:26 +08:00
|
|
|
break;
|
|
|
|
case A84_DIAG_LOGIN_COMPLETE:
|
|
|
|
ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x501b,
|
|
|
|
"Alert 84XX: diagnostic firmware version %x.\n",
|
|
|
|
ha->cs84xx->diag_fw_version);
|
2008-04-04 04:13:26 +08:00
|
|
|
break;
|
|
|
|
case A84_GOLD_LOGIN_COMPLETE:
|
|
|
|
ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
|
|
|
|
ha->cs84xx->fw_update = 1;
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x501c,
|
|
|
|
"Alert 84XX: gold firmware version %x.\n",
|
|
|
|
ha->cs84xx->gold_fw_version);
|
2008-04-04 04:13:26 +08:00
|
|
|
break;
|
|
|
|
default:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x501d,
|
|
|
|
"Alert 84xx: Invalid Alert %04x %04x %04x.\n",
|
2008-04-04 04:13:26 +08:00
|
|
|
mb[1], mb[2], mb[3]);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
|
|
|
|
break;
|
2009-01-06 03:18:11 +08:00
|
|
|
case MBA_DCBX_START:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x501e,
|
|
|
|
"DCBX Started -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2009-01-06 03:18:11 +08:00
|
|
|
break;
|
|
|
|
case MBA_DCBX_PARAM_UPDATE:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x501f,
|
|
|
|
"DCBX Parameters Updated -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2009-01-06 03:18:11 +08:00
|
|
|
break;
|
|
|
|
case MBA_FCF_CONF_ERR:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5020,
|
|
|
|
"FCF Configuration Error -- %04x %04x %04x.\n",
|
|
|
|
mb[1], mb[2], mb[3]);
|
2009-01-06 03:18:11 +08:00
|
|
|
break;
|
|
|
|
case MBA_IDC_NOTIFY:
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
|
2013-02-08 14:57:51 +08:00
|
|
|
mb[4] = RD_REG_WORD(®24->mailbox4);
|
|
|
|
if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
|
|
|
|
(mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
|
|
|
|
(mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
|
2012-08-23 02:21:06 +08:00
|
|
|
set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
|
2013-02-08 14:57:51 +08:00
|
|
|
/*
|
|
|
|
* Extend loop down timer since port is active.
|
|
|
|
*/
|
|
|
|
if (atomic_read(&vha->loop_state) == LOOP_DOWN)
|
|
|
|
atomic_set(&vha->loop_down_timer,
|
|
|
|
LOOP_DOWN_TIME);
|
2012-08-23 02:21:06 +08:00
|
|
|
qla2xxx_wake_dpc(vha);
|
|
|
|
}
|
2013-02-08 14:57:51 +08:00
|
|
|
}
|
2017-12-08 08:02:46 +08:00
|
|
|
/* fall through */
|
2012-08-23 02:21:06 +08:00
|
|
|
case MBA_IDC_COMPLETE:
|
2013-10-30 15:38:25 +08:00
|
|
|
if (ha->notify_lb_portup_comp && !vha->vp_idx)
|
2013-02-08 14:58:04 +08:00
|
|
|
complete(&ha->lb_portup_comp);
|
|
|
|
/* Fallthru */
|
2009-01-06 03:18:11 +08:00
|
|
|
case MBA_IDC_TIME_EXT:
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
|
|
|
|
IS_QLA8044(ha))
|
2012-08-23 02:21:03 +08:00
|
|
|
qla81xx_idc_event(vha, mb[0], mb[1]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MBA_IDC_AEN:
|
|
|
|
mb[4] = RD_REG_WORD(®24->mailbox4);
|
|
|
|
mb[5] = RD_REG_WORD(®24->mailbox5);
|
|
|
|
mb[6] = RD_REG_WORD(®24->mailbox6);
|
|
|
|
mb[7] = RD_REG_WORD(®24->mailbox7);
|
|
|
|
qla83xx_handle_8200_aen(vha, mb);
|
2009-01-06 03:18:11 +08:00
|
|
|
break;
|
2012-08-23 02:21:03 +08:00
|
|
|
|
2014-09-25 17:16:48 +08:00
|
|
|
case MBA_DPORT_DIAGNOSTICS:
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5052,
|
2016-07-06 23:14:30 +08:00
|
|
|
"D-Port Diagnostics: %04x result=%s\n",
|
2016-07-06 23:14:26 +08:00
|
|
|
mb[0],
|
2014-09-25 17:16:48 +08:00
|
|
|
mb[1] == 0 ? "start" :
|
2016-07-06 23:14:30 +08:00
|
|
|
mb[1] == 1 ? "done (pass)" :
|
|
|
|
mb[1] == 2 ? "done (error)" : "other");
|
2014-09-25 17:16:48 +08:00
|
|
|
break;
|
|
|
|
|
2016-07-06 23:14:19 +08:00
|
|
|
case MBA_TEMPERATURE_ALERT:
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x505e,
|
|
|
|
"TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
|
|
|
|
if (mb[1] == 0x12)
|
|
|
|
schedule_work(&ha->board_disable);
|
|
|
|
break;
|
|
|
|
|
2017-08-24 06:05:16 +08:00
|
|
|
case MBA_TRANS_INSERT:
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5091,
|
|
|
|
"Transceiver Insertion: %04x\n", mb[1]);
|
|
|
|
break;
|
|
|
|
|
2012-02-10 03:15:34 +08:00
|
|
|
default:
|
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5057,
|
|
|
|
"Unknown AEN:%04x %04x %04x %04x\n",
|
|
|
|
mb[0], mb[1], mb[2], mb[3]);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-07-06 04:16:51 +08:00
|
|
|
|
2012-05-16 02:34:28 +08:00
|
|
|
qlt_async_event(mb[0], vha, mb);
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (!vha->vp_idx && ha->num_vhosts)
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_alert_all_vps(rsp, mb);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_process_completed_request() - Process a Fast Post response.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
|
|
|
* @req: request queue
|
2005-04-17 06:20:36 +08:00
|
|
|
* @index: SRB index
|
|
|
|
*/
|
2013-03-28 20:21:23 +08:00
|
|
|
void
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_completed_request(struct scsi_qla_host *vha,
|
2013-03-28 20:21:23 +08:00
|
|
|
struct req_que *req, uint32_t index)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
srb_t *sp;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Validate handle. */
|
2013-01-30 16:34:37 +08:00
|
|
|
if (index >= req->num_outstanding_cmds) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x3014,
|
|
|
|
"Invalid SCSI command index (%x).\n", index);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_P3P_TYPE(ha))
|
2011-03-31 02:46:26 +08:00
|
|
|
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
sp = req->outstanding_cmds[index];
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sp) {
|
|
|
|
/* Free outstanding command slot. */
|
2008-11-07 02:40:51 +08:00
|
|
|
req->outstanding_cmds[index] = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Save ISP completion status */
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, DID_OK << 16);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_P3P_TYPE(ha))
|
2011-03-31 02:46:26 +08:00
|
|
|
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 20:21:23 +08:00
|
|
|
srb_t *
|
2009-08-21 02:06:05 +08:00
|
|
|
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
|
|
|
struct req_que *req, void *iocb)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
sts_entry_t *pkt = iocb;
|
|
|
|
srb_t *sp = NULL;
|
|
|
|
uint16_t index;
|
|
|
|
|
|
|
|
index = LSW(pkt->handle);
|
2013-01-30 16:34:37 +08:00
|
|
|
if (index >= req->num_outstanding_cmds) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5031,
|
2017-01-20 14:28:00 +08:00
|
|
|
"Invalid command index (%x) type %8ph.\n",
|
|
|
|
index, iocb);
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_P3P_TYPE(ha))
|
2011-03-31 02:46:26 +08:00
|
|
|
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2009-08-21 02:06:05 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
sp = req->outstanding_cmds[index];
|
|
|
|
if (!sp) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5032,
|
|
|
|
"Invalid completion handle (%x) -- timed-out.\n", index);
|
2009-08-21 02:06:05 +08:00
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
if (sp->handle != index) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5033,
|
|
|
|
"SRB handle (%x) mismatch %x.\n", sp->handle, index);
|
2009-08-21 02:06:05 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-01-13 05:02:47 +08:00
|
|
|
|
2009-08-21 02:06:05 +08:00
|
|
|
req->outstanding_cmds[index] = NULL;
|
2010-01-13 05:02:47 +08:00
|
|
|
|
2009-08-21 02:06:05 +08:00
|
|
|
done:
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct mbx_entry *mbx)
|
|
|
|
{
|
|
|
|
const char func[] = "MBX-IOCB";
|
|
|
|
const char *type;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
srb_t *sp;
|
2010-05-05 06:01:28 +08:00
|
|
|
struct srb_iocb *lio;
|
2010-05-05 06:01:25 +08:00
|
|
|
uint16_t *data;
|
2010-05-05 06:01:26 +08:00
|
|
|
uint16_t status;
|
2009-08-21 02:06:05 +08:00
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
lio = &sp->u.iocb_cmd;
|
|
|
|
type = sp->name;
|
2009-08-21 02:06:05 +08:00
|
|
|
fcport = sp->fcport;
|
2010-05-05 06:01:28 +08:00
|
|
|
data = lio->u.logio.data;
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:26 +08:00
|
|
|
data[0] = MBS_COMMAND_ERROR;
|
2010-05-05 06:01:28 +08:00
|
|
|
data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
|
2010-05-05 06:01:26 +08:00
|
|
|
QLA_LOGIO_LOGIN_RETRIED : 0;
|
2009-08-21 02:06:05 +08:00
|
|
|
if (mbx->entry_status) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5043,
|
2011-11-19 01:03:07 +08:00
|
|
|
"Async-%s error entry - hdl=%x portid=%02x%02x%02x "
|
2010-05-29 06:08:16 +08:00
|
|
|
"entry-status=%x status=%x state-flag=%x "
|
2011-11-19 01:03:07 +08:00
|
|
|
"status-flags=%x.\n", type, sp->handle,
|
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
2010-05-29 06:08:16 +08:00
|
|
|
fcport->d_id.b.al_pa, mbx->entry_status,
|
|
|
|
le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
|
2011-07-15 03:00:13 +08:00
|
|
|
le16_to_cpu(mbx->status_flags));
|
2010-05-29 06:08:16 +08:00
|
|
|
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
|
2019-03-13 02:08:16 +08:00
|
|
|
mbx, sizeof(*mbx));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:25 +08:00
|
|
|
goto logio_done;
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
2010-05-05 06:01:26 +08:00
|
|
|
status = le16_to_cpu(mbx->status);
|
2012-02-10 03:15:36 +08:00
|
|
|
if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
|
2010-05-05 06:01:26 +08:00
|
|
|
le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
|
|
|
|
status = 0;
|
|
|
|
if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5045,
|
2011-11-19 01:03:07 +08:00
|
|
|
"Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n",
|
|
|
|
type, sp->handle, fcport->d_id.b.domain,
|
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
|
|
|
le16_to_cpu(mbx->mb1));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
|
|
|
data[0] = MBS_COMMAND_COMPLETE;
|
2012-02-10 03:15:36 +08:00
|
|
|
if (sp->type == SRB_LOGIN_CMD) {
|
2010-05-05 06:01:25 +08:00
|
|
|
fcport->port_type = FCT_TARGET;
|
|
|
|
if (le16_to_cpu(mbx->mb1) & BIT_0)
|
|
|
|
fcport->port_type = FCT_INITIATOR;
|
2010-05-29 06:08:19 +08:00
|
|
|
else if (le16_to_cpu(mbx->mb1) & BIT_1)
|
2010-05-05 06:01:25 +08:00
|
|
|
fcport->flags |= FCF_FCP2_DEVICE;
|
2010-05-05 06:01:26 +08:00
|
|
|
}
|
2010-05-05 06:01:25 +08:00
|
|
|
goto logio_done;
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
data[0] = le16_to_cpu(mbx->mb0);
|
|
|
|
switch (data[0]) {
|
|
|
|
case MBS_PORT_ID_USED:
|
|
|
|
data[1] = le16_to_cpu(mbx->mb1);
|
|
|
|
break;
|
|
|
|
case MBS_LOOP_ID_USED:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
data[0] = MBS_COMMAND_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x5046,
|
2011-11-19 01:03:07 +08:00
|
|
|
"Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x "
|
|
|
|
"mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle,
|
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
|
|
|
status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
|
2009-08-21 02:06:05 +08:00
|
|
|
le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
|
2011-07-15 03:00:13 +08:00
|
|
|
le16_to_cpu(mbx->mb7));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:25 +08:00
|
|
|
logio_done:
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, 0);
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
static void
|
|
|
|
qla24xx_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct mbx_24xx_entry *pkt)
|
|
|
|
{
|
|
|
|
const char func[] = "MBX-IOCB2";
|
|
|
|
srb_t *sp;
|
|
|
|
struct srb_iocb *si;
|
|
|
|
u16 sz, i;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
si = &sp->u.iocb_cmd;
|
|
|
|
sz = min(ARRAY_SIZE(pkt->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.in_mb));
|
|
|
|
|
|
|
|
for (i = 0; i < sz; i++)
|
|
|
|
si->u.mbx.in_mb[i] = le16_to_cpu(pkt->mb[i]);
|
|
|
|
|
|
|
|
res = (si->u.mbx.in_mb[0] & MBS_MASK);
|
|
|
|
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2017-01-20 14:28:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qla24xxx_nack_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct nack_to_isp *pkt)
|
|
|
|
{
|
|
|
|
const char func[] = "nack";
|
|
|
|
srb_t *sp;
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pkt->u.isp2x.status != cpu_to_le16(NOTIFY_ACK_SUCCESS))
|
|
|
|
res = QLA_FUNCTION_FAILED;
|
|
|
|
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
2010-07-23 18:28:32 +08:00
|
|
|
static void
|
|
|
|
qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
sts_entry_t *pkt, int iocb_type)
|
|
|
|
{
|
|
|
|
const char func[] = "CT_IOCB";
|
|
|
|
const char *type;
|
|
|
|
srb_t *sp;
|
2016-11-17 17:31:19 +08:00
|
|
|
struct bsg_job *bsg_job;
|
2016-11-17 17:31:12 +08:00
|
|
|
struct fc_bsg_reply *bsg_reply;
|
2010-07-23 18:28:32 +08:00
|
|
|
uint16_t comp_status;
|
2017-01-20 14:28:00 +08:00
|
|
|
int res = 0;
|
2010-07-23 18:28:32 +08:00
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
switch (sp->type) {
|
|
|
|
case SRB_CT_CMD:
|
|
|
|
bsg_job = sp->u.bsg_job;
|
|
|
|
bsg_reply = bsg_job->reply;
|
|
|
|
|
|
|
|
type = "ct pass-through";
|
|
|
|
|
|
|
|
comp_status = le16_to_cpu(pkt->comp_status);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
|
|
|
|
* fc payload to the caller
|
|
|
|
*/
|
|
|
|
bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
|
|
|
|
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
|
|
|
|
|
|
|
if (comp_status != CS_COMPLETE) {
|
|
|
|
if (comp_status == CS_DATA_UNDERRUN) {
|
|
|
|
res = DID_OK << 16;
|
|
|
|
bsg_reply->reply_payload_rcv_len =
|
|
|
|
le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
|
|
|
|
|
|
|
|
ql_log(ql_log_warn, vha, 0x5048,
|
|
|
|
"CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n",
|
|
|
|
type, comp_status,
|
|
|
|
bsg_reply->reply_payload_rcv_len);
|
|
|
|
} else {
|
|
|
|
ql_log(ql_log_warn, vha, 0x5049,
|
|
|
|
"CT pass-through-%s error comp_status=0x%x.\n",
|
|
|
|
type, comp_status);
|
|
|
|
res = DID_ERROR << 16;
|
|
|
|
bsg_reply->reply_payload_rcv_len = 0;
|
|
|
|
}
|
|
|
|
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
|
2019-03-13 02:08:16 +08:00
|
|
|
pkt, sizeof(*pkt));
|
2017-01-20 14:28:00 +08:00
|
|
|
} else {
|
|
|
|
res = DID_OK << 16;
|
|
|
|
bsg_reply->reply_payload_rcv_len =
|
|
|
|
bsg_job->reply_payload.payload_len;
|
|
|
|
bsg_job->reply_len = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SRB_CT_PTHRU_CMD:
|
|
|
|
/*
|
|
|
|
* borrowing sts_entry_24xx.comp_status.
|
|
|
|
* same location as ct_entry_24xx.comp_status
|
|
|
|
*/
|
|
|
|
res = qla2x00_chk_ms_status(vha, (ms_iocb_entry_t *)pkt,
|
|
|
|
(struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
|
|
|
|
sp->name);
|
|
|
|
break;
|
2010-07-23 18:28:32 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2010-07-23 18:28:32 +08:00
|
|
|
}
|
|
|
|
|
2010-01-13 05:02:47 +08:00
|
|
|
static void
|
|
|
|
qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct sts_entry_24xx *pkt, int iocb_type)
|
|
|
|
{
|
|
|
|
const char func[] = "ELS_CT_IOCB";
|
|
|
|
const char *type;
|
|
|
|
srb_t *sp;
|
2016-11-17 17:31:19 +08:00
|
|
|
struct bsg_job *bsg_job;
|
2016-11-17 17:31:12 +08:00
|
|
|
struct fc_bsg_reply *bsg_reply;
|
2010-01-13 05:02:47 +08:00
|
|
|
uint16_t comp_status;
|
|
|
|
uint32_t fw_status[3];
|
2012-02-10 03:15:36 +08:00
|
|
|
int res;
|
2017-10-14 00:34:06 +08:00
|
|
|
struct srb_iocb *els;
|
2010-01-13 05:02:47 +08:00
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
type = NULL;
|
2012-02-10 03:15:36 +08:00
|
|
|
switch (sp->type) {
|
2010-01-13 05:02:47 +08:00
|
|
|
case SRB_ELS_CMD_RPT:
|
|
|
|
case SRB_ELS_CMD_HST:
|
|
|
|
type = "els";
|
|
|
|
break;
|
|
|
|
case SRB_CT_CMD:
|
|
|
|
type = "ct pass-through";
|
|
|
|
break;
|
2015-12-18 03:57:00 +08:00
|
|
|
case SRB_ELS_DCMD:
|
|
|
|
type = "Driver ELS logo";
|
2017-10-14 00:34:06 +08:00
|
|
|
if (iocb_type != ELS_IOCB_TYPE) {
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x5047,
|
|
|
|
"Completing %s: (%p) type=%d.\n",
|
|
|
|
type, sp, sp->type);
|
|
|
|
sp->done(sp, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2017-01-20 14:28:00 +08:00
|
|
|
case SRB_CT_PTHRU_CMD:
|
|
|
|
/* borrowing sts_entry_24xx.comp_status.
|
|
|
|
same location as ct_entry_24xx.comp_status
|
|
|
|
*/
|
2017-12-05 06:45:02 +08:00
|
|
|
res = qla2x00_chk_ms_status(sp->vha, (ms_iocb_entry_t *)pkt,
|
2017-01-20 14:28:00 +08:00
|
|
|
(struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
|
|
|
|
sp->name);
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2015-12-18 03:57:00 +08:00
|
|
|
return;
|
2010-01-13 05:02:47 +08:00
|
|
|
default:
|
2012-02-10 03:15:37 +08:00
|
|
|
ql_dbg(ql_dbg_user, vha, 0x503e,
|
2012-02-10 03:15:36 +08:00
|
|
|
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
|
2010-01-13 05:02:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
|
2019-04-12 05:53:18 +08:00
|
|
|
fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1);
|
|
|
|
fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2);
|
2010-01-13 05:02:47 +08:00
|
|
|
|
2017-10-14 00:34:06 +08:00
|
|
|
if (iocb_type == ELS_IOCB_TYPE) {
|
|
|
|
els = &sp->u.iocb_cmd;
|
|
|
|
els->u.els_plogi.fw_status[0] = fw_status[0];
|
|
|
|
els->u.els_plogi.fw_status[1] = fw_status[1];
|
|
|
|
els->u.els_plogi.fw_status[2] = fw_status[2];
|
|
|
|
els->u.els_plogi.comp_status = fw_status[0];
|
|
|
|
if (comp_status == CS_COMPLETE) {
|
|
|
|
res = DID_OK << 16;
|
|
|
|
} else {
|
|
|
|
if (comp_status == CS_DATA_UNDERRUN) {
|
|
|
|
res = DID_OK << 16;
|
|
|
|
els->u.els_plogi.len =
|
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)
|
|
|
|
pkt)->total_byte_count);
|
|
|
|
} else {
|
|
|
|
els->u.els_plogi.len = 0;
|
|
|
|
res = DID_ERROR << 16;
|
|
|
|
}
|
|
|
|
}
|
2019-04-24 05:52:36 +08:00
|
|
|
ql_dbg(ql_dbg_user, vha, 0x503f,
|
2017-10-14 00:34:06 +08:00
|
|
|
"ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
|
|
|
|
type, sp->handle, comp_status, fw_status[1], fw_status[2],
|
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)
|
|
|
|
pkt)->total_byte_count));
|
|
|
|
goto els_ct_done;
|
|
|
|
}
|
|
|
|
|
2010-01-13 05:02:47 +08:00
|
|
|
/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
|
|
|
|
* fc payload to the caller
|
|
|
|
*/
|
2017-08-24 06:05:01 +08:00
|
|
|
bsg_job = sp->u.bsg_job;
|
|
|
|
bsg_reply = bsg_job->reply;
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
|
2010-01-13 05:02:47 +08:00
|
|
|
bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
|
|
|
|
|
|
|
|
if (comp_status != CS_COMPLETE) {
|
|
|
|
if (comp_status == CS_DATA_UNDERRUN) {
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_OK << 16;
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len =
|
2012-02-10 03:15:36 +08:00
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->total_byte_count);
|
2010-01-13 05:02:47 +08:00
|
|
|
|
2012-02-10 03:15:37 +08:00
|
|
|
ql_dbg(ql_dbg_user, vha, 0x503f,
|
2011-11-19 01:03:07 +08:00
|
|
|
"ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
|
2010-01-13 05:02:47 +08:00
|
|
|
"error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
|
2011-11-19 01:03:07 +08:00
|
|
|
type, sp->handle, comp_status, fw_status[1], fw_status[2],
|
2011-07-15 03:00:13 +08:00
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)
|
|
|
|
pkt)->total_byte_count));
|
2017-10-03 18:48:40 +08:00
|
|
|
} else {
|
2012-02-10 03:15:37 +08:00
|
|
|
ql_dbg(ql_dbg_user, vha, 0x5040,
|
2011-11-19 01:03:07 +08:00
|
|
|
"ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
|
2010-01-13 05:02:47 +08:00
|
|
|
"error subcode 1=0x%x error subcode 2=0x%x.\n",
|
2011-11-19 01:03:07 +08:00
|
|
|
type, sp->handle, comp_status,
|
2011-07-15 03:00:13 +08:00
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)
|
|
|
|
pkt)->error_subcode_1),
|
|
|
|
le16_to_cpu(((struct els_sts_entry_24xx *)
|
|
|
|
pkt)->error_subcode_2));
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16;
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len = 0;
|
2010-01-13 05:02:47 +08:00
|
|
|
}
|
2017-10-03 18:48:40 +08:00
|
|
|
memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply),
|
|
|
|
fw_status, sizeof(fw_status));
|
2012-02-10 03:15:37 +08:00
|
|
|
ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
|
2019-03-13 02:08:16 +08:00
|
|
|
pkt, sizeof(*pkt));
|
2010-01-13 05:02:47 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_OK << 16;
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
|
2010-01-13 05:02:47 +08:00
|
|
|
bsg_job->reply_len = 0;
|
|
|
|
}
|
2017-10-14 00:34:06 +08:00
|
|
|
els_ct_done:
|
2010-01-13 05:02:47 +08:00
|
|
|
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2010-01-13 05:02:47 +08:00
|
|
|
}
|
|
|
|
|
2009-08-21 02:06:05 +08:00
|
|
|
static void
|
|
|
|
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct logio_entry_24xx *logio)
|
|
|
|
{
|
|
|
|
const char func[] = "LOGIO-IOCB";
|
|
|
|
const char *type;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
srb_t *sp;
|
2010-05-05 06:01:28 +08:00
|
|
|
struct srb_iocb *lio;
|
2010-05-05 06:01:25 +08:00
|
|
|
uint16_t *data;
|
2009-08-21 02:06:05 +08:00
|
|
|
uint32_t iop[2];
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
lio = &sp->u.iocb_cmd;
|
|
|
|
type = sp->name;
|
2009-08-21 02:06:05 +08:00
|
|
|
fcport = sp->fcport;
|
2010-05-05 06:01:28 +08:00
|
|
|
data = lio->u.logio.data;
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:26 +08:00
|
|
|
data[0] = MBS_COMMAND_ERROR;
|
2010-05-05 06:01:28 +08:00
|
|
|
data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
|
2010-05-05 06:01:26 +08:00
|
|
|
QLA_LOGIO_LOGIN_RETRIED : 0;
|
2009-08-21 02:06:05 +08:00
|
|
|
if (logio->entry_status) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x5034,
|
2017-03-16 00:48:48 +08:00
|
|
|
"Async-%s error entry - %8phC hdl=%x"
|
2010-05-29 06:08:16 +08:00
|
|
|
"portid=%02x%02x%02x entry-status=%x.\n",
|
2017-03-16 00:48:48 +08:00
|
|
|
type, fcport->port_name, sp->handle, fcport->d_id.b.domain,
|
2011-11-19 01:03:07 +08:00
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
|
|
|
logio->entry_status);
|
|
|
|
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
|
2019-03-13 02:08:16 +08:00
|
|
|
logio, sizeof(*logio));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:25 +08:00
|
|
|
goto logio_done;
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_async, fcport->vha, 0x5036,
|
2017-03-16 00:48:48 +08:00
|
|
|
"Async-%s complete - %8phC hdl=%x portid=%02x%02x%02x "
|
|
|
|
"iop0=%x.\n", type, fcport->port_name, sp->handle,
|
|
|
|
fcport->d_id.b.domain,
|
2011-11-19 01:03:07 +08:00
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
2011-07-15 03:00:13 +08:00
|
|
|
le32_to_cpu(logio->io_parameter[0]));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2017-01-20 14:28:01 +08:00
|
|
|
vha->hw->exch_starvation = 0;
|
2009-08-21 02:06:05 +08:00
|
|
|
data[0] = MBS_COMMAND_COMPLETE;
|
2019-02-16 06:37:13 +08:00
|
|
|
|
|
|
|
if (sp->type == SRB_PRLI_CMD) {
|
|
|
|
lio->u.logio.iop[0] =
|
|
|
|
le32_to_cpu(logio->io_parameter[0]);
|
|
|
|
lio->u.logio.iop[1] =
|
|
|
|
le32_to_cpu(logio->io_parameter[1]);
|
|
|
|
goto logio_done;
|
|
|
|
}
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
if (sp->type != SRB_LOGIN_CMD)
|
2010-05-05 06:01:25 +08:00
|
|
|
goto logio_done;
|
2009-08-21 02:06:05 +08:00
|
|
|
|
|
|
|
iop[0] = le32_to_cpu(logio->io_parameter[0]);
|
|
|
|
if (iop[0] & BIT_4) {
|
|
|
|
fcport->port_type = FCT_TARGET;
|
|
|
|
if (iop[0] & BIT_8)
|
2009-08-26 02:36:16 +08:00
|
|
|
fcport->flags |= FCF_FCP2_DEVICE;
|
2010-05-29 06:08:22 +08:00
|
|
|
} else if (iop[0] & BIT_5)
|
2009-08-21 02:06:05 +08:00
|
|
|
fcport->port_type = FCT_INITIATOR;
|
2010-05-29 06:08:22 +08:00
|
|
|
|
2012-05-16 02:34:28 +08:00
|
|
|
if (iop[0] & BIT_7)
|
|
|
|
fcport->flags |= FCF_CONF_COMP_SUPPORTED;
|
|
|
|
|
2009-08-21 02:06:05 +08:00
|
|
|
if (logio->io_parameter[7] || logio->io_parameter[8])
|
|
|
|
fcport->supported_classes |= FC_COS_CLASS2;
|
|
|
|
if (logio->io_parameter[9] || logio->io_parameter[10])
|
|
|
|
fcport->supported_classes |= FC_COS_CLASS3;
|
|
|
|
|
2010-05-05 06:01:25 +08:00
|
|
|
goto logio_done;
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
iop[0] = le32_to_cpu(logio->io_parameter[0]);
|
|
|
|
iop[1] = le32_to_cpu(logio->io_parameter[1]);
|
2017-01-20 14:28:00 +08:00
|
|
|
lio->u.logio.iop[0] = iop[0];
|
|
|
|
lio->u.logio.iop[1] = iop[1];
|
2009-08-21 02:06:05 +08:00
|
|
|
switch (iop[0]) {
|
|
|
|
case LSC_SCODE_PORTID_USED:
|
|
|
|
data[0] = MBS_PORT_ID_USED;
|
|
|
|
data[1] = LSW(iop[1]);
|
|
|
|
break;
|
|
|
|
case LSC_SCODE_NPORT_USED:
|
|
|
|
data[0] = MBS_LOOP_ID_USED;
|
|
|
|
break;
|
2017-03-16 00:48:48 +08:00
|
|
|
case LSC_SCODE_CMD_FAILED:
|
|
|
|
if (iop[1] == 0x0606) {
|
|
|
|
/*
|
|
|
|
* PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI,
|
|
|
|
* Target side acked.
|
|
|
|
*/
|
|
|
|
data[0] = MBS_COMMAND_COMPLETE;
|
|
|
|
goto logio_done;
|
|
|
|
}
|
|
|
|
data[0] = MBS_COMMAND_ERROR;
|
|
|
|
break;
|
2017-01-20 14:28:01 +08:00
|
|
|
case LSC_SCODE_NOXCB:
|
|
|
|
vha->hw->exch_starvation++;
|
|
|
|
if (vha->hw->exch_starvation > 5) {
|
2017-06-03 00:12:01 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0xd046,
|
2017-01-20 14:28:01 +08:00
|
|
|
"Exchange starvation. Resetting RISC\n");
|
|
|
|
|
|
|
|
vha->hw->exch_starvation = 0;
|
|
|
|
|
|
|
|
if (IS_P3P_TYPE(vha->hw))
|
|
|
|
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
|
|
|
qla2xxx_wake_dpc(vha);
|
|
|
|
}
|
2017-12-08 08:02:46 +08:00
|
|
|
/* fall through */
|
2009-08-21 02:06:05 +08:00
|
|
|
default:
|
|
|
|
data[0] = MBS_COMMAND_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_async, fcport->vha, 0x5037,
|
2017-03-16 00:48:48 +08:00
|
|
|
"Async-%s failed - %8phC hdl=%x portid=%02x%02x%02x comp=%x "
|
|
|
|
"iop0=%x iop1=%x.\n", type, fcport->port_name,
|
|
|
|
sp->handle, fcport->d_id.b.domain,
|
2010-05-29 06:08:16 +08:00
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
2009-08-21 02:06:05 +08:00
|
|
|
le16_to_cpu(logio->comp_status),
|
|
|
|
le32_to_cpu(logio->io_parameter[0]),
|
2011-07-15 03:00:13 +08:00
|
|
|
le32_to_cpu(logio->io_parameter[1]));
|
2009-08-21 02:06:05 +08:00
|
|
|
|
2010-05-05 06:01:25 +08:00
|
|
|
logio_done:
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, 0);
|
2009-08-21 02:06:05 +08:00
|
|
|
}
|
|
|
|
|
2010-05-05 06:01:29 +08:00
|
|
|
static void
|
2014-02-26 17:15:17 +08:00
|
|
|
qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
|
2010-05-05 06:01:29 +08:00
|
|
|
{
|
|
|
|
const char func[] = "TMF-IOCB";
|
|
|
|
const char *type;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
srb_t *sp;
|
|
|
|
struct srb_iocb *iocb;
|
|
|
|
struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
iocb = &sp->u.iocb_cmd;
|
|
|
|
type = sp->name;
|
2010-05-05 06:01:29 +08:00
|
|
|
fcport = sp->fcport;
|
2014-02-26 17:15:17 +08:00
|
|
|
iocb->u.tmf.data = QLA_SUCCESS;
|
2010-05-05 06:01:29 +08:00
|
|
|
|
|
|
|
if (sts->entry_status) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x5038,
|
2011-11-19 01:03:07 +08:00
|
|
|
"Async-%s error - hdl=%x entry-status(%x).\n",
|
|
|
|
type, sp->handle, sts->entry_status);
|
2014-02-26 17:15:17 +08:00
|
|
|
iocb->u.tmf.data = QLA_FUNCTION_FAILED;
|
2015-07-09 22:24:08 +08:00
|
|
|
} else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x5039,
|
2011-11-19 01:03:07 +08:00
|
|
|
"Async-%s error - hdl=%x completion status(%x).\n",
|
|
|
|
type, sp->handle, sts->comp_status);
|
2014-02-26 17:15:17 +08:00
|
|
|
iocb->u.tmf.data = QLA_FUNCTION_FAILED;
|
|
|
|
} else if ((le16_to_cpu(sts->scsi_status) &
|
2010-05-05 06:01:29 +08:00
|
|
|
SS_RESPONSE_INFO_LEN_VALID)) {
|
2014-02-26 17:15:17 +08:00
|
|
|
if (le32_to_cpu(sts->rsp_data_len) < 4) {
|
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x503b,
|
|
|
|
"Async-%s error - hdl=%x not enough response(%d).\n",
|
|
|
|
type, sp->handle, sts->rsp_data_len);
|
|
|
|
} else if (sts->data[3]) {
|
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x503c,
|
|
|
|
"Async-%s error - hdl=%x response(%x).\n",
|
|
|
|
type, sp->handle, sts->data[3]);
|
2015-06-05 06:58:09 +08:00
|
|
|
iocb->u.tmf.data = QLA_FUNCTION_FAILED;
|
2014-02-26 17:15:17 +08:00
|
|
|
}
|
2010-05-05 06:01:29 +08:00
|
|
|
}
|
|
|
|
|
2014-02-26 17:15:17 +08:00
|
|
|
if (iocb->u.tmf.data != QLA_SUCCESS)
|
2019-03-13 02:08:16 +08:00
|
|
|
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
|
|
|
|
sts, sizeof(*sts));
|
2010-05-05 06:01:29 +08:00
|
|
|
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, 0);
|
2010-05-05 06:01:29 +08:00
|
|
|
}
|
|
|
|
|
2018-03-21 14:09:39 +08:00
|
|
|
static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
void *tsk, srb_t *sp)
|
2017-06-22 04:48:42 +08:00
|
|
|
{
|
|
|
|
fc_port_t *fcport;
|
|
|
|
struct srb_iocb *iocb;
|
|
|
|
struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
|
|
|
|
uint16_t state_flags;
|
|
|
|
struct nvmefc_fcp_req *fd;
|
2018-09-12 01:18:12 +08:00
|
|
|
uint16_t ret = QLA_SUCCESS;
|
|
|
|
uint16_t comp_status = le16_to_cpu(sts->comp_status);
|
2017-06-22 04:48:42 +08:00
|
|
|
|
|
|
|
iocb = &sp->u.iocb_cmd;
|
|
|
|
fcport = sp->fcport;
|
2018-09-12 01:18:12 +08:00
|
|
|
iocb->u.nvme.comp_status = comp_status;
|
2017-06-22 04:48:42 +08:00
|
|
|
state_flags = le16_to_cpu(sts->state_flags);
|
|
|
|
fd = iocb->u.nvme.desc;
|
|
|
|
|
2018-03-21 14:09:39 +08:00
|
|
|
if (unlikely(iocb->u.nvme.aen_op))
|
2017-07-22 00:32:25 +08:00
|
|
|
atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
|
2017-06-22 04:48:42 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* State flags: Bit 6 and 0.
|
|
|
|
* If 0 is set, we don't care about 6.
|
|
|
|
* both cases resp was dma'd to host buffer
|
|
|
|
* if both are 0, that is good path case.
|
|
|
|
* if six is set and 0 is clear, we need to
|
|
|
|
* copy resp data from status iocb to resp buffer.
|
|
|
|
*/
|
|
|
|
if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) {
|
|
|
|
iocb->u.nvme.rsp_pyld_len = 0;
|
|
|
|
} else if ((state_flags & SF_FCP_RSP_DMA)) {
|
|
|
|
iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len);
|
|
|
|
} else if (state_flags & SF_NVME_ERSP) {
|
|
|
|
uint32_t *inbuf, *outbuf;
|
|
|
|
uint16_t iter;
|
|
|
|
|
|
|
|
inbuf = (uint32_t *)&sts->nvme_ersp_data;
|
|
|
|
outbuf = (uint32_t *)fd->rspaddr;
|
|
|
|
iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len);
|
|
|
|
iter = iocb->u.nvme.rsp_pyld_len >> 2;
|
|
|
|
for (; iter; iter--)
|
|
|
|
*outbuf++ = swab32(*inbuf++);
|
|
|
|
} else { /* unhandled case */
|
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x503a,
|
|
|
|
"NVME-%s error. Unhandled state_flags of %x\n",
|
|
|
|
sp->name, state_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
fd->transferred_length = fd->payload_length -
|
|
|
|
le32_to_cpu(sts->residual_len);
|
|
|
|
|
2018-09-12 01:18:12 +08:00
|
|
|
if (unlikely(comp_status != CS_COMPLETE))
|
|
|
|
ql_log(ql_log_warn, fcport->vha, 0x5060,
|
|
|
|
"NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n",
|
|
|
|
sp->name, sp->handle, comp_status,
|
|
|
|
fd->transferred_length, le32_to_cpu(sts->residual_len),
|
|
|
|
sts->ox_id);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If transport error then Failure (HBA rejects request)
|
|
|
|
* otherwise transport will handle.
|
|
|
|
*/
|
|
|
|
switch (comp_status) {
|
2018-03-21 14:09:39 +08:00
|
|
|
case CS_COMPLETE:
|
|
|
|
break;
|
2018-09-12 01:18:12 +08:00
|
|
|
|
2018-03-21 14:09:39 +08:00
|
|
|
case CS_RESET:
|
|
|
|
case CS_PORT_UNAVAILABLE:
|
|
|
|
case CS_PORT_LOGGED_OUT:
|
2018-09-12 01:18:12 +08:00
|
|
|
fcport->nvme_flag |= NVME_FLAG_RESETTING;
|
|
|
|
/* fall through */
|
|
|
|
case CS_ABORTED:
|
2018-03-21 14:09:39 +08:00
|
|
|
case CS_PORT_BUSY:
|
|
|
|
fd->transferred_length = 0;
|
|
|
|
iocb->u.nvme.rsp_pyld_len = 0;
|
|
|
|
ret = QLA_ABORTED;
|
|
|
|
break;
|
2018-09-12 01:18:12 +08:00
|
|
|
case CS_DATA_UNDERRUN:
|
|
|
|
break;
|
2018-03-21 14:09:39 +08:00
|
|
|
default:
|
2017-06-22 04:48:42 +08:00
|
|
|
ret = QLA_FUNCTION_FAILED;
|
2018-03-21 14:09:39 +08:00
|
|
|
break;
|
2017-06-22 04:48:42 +08:00
|
|
|
}
|
|
|
|
sp->done(sp, ret);
|
|
|
|
}
|
|
|
|
|
2017-12-29 04:33:10 +08:00
|
|
|
static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct vp_ctrl_entry_24xx *vce)
|
|
|
|
{
|
|
|
|
const char func[] = "CTRLVP-IOCB";
|
|
|
|
srb_t *sp;
|
|
|
|
int rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, vce);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (vce->entry_status != 0) {
|
|
|
|
ql_dbg(ql_dbg_vport, vha, 0x10c4,
|
|
|
|
"%s: Failed to complete IOCB -- error status (%x)\n",
|
|
|
|
sp->name, vce->entry_status);
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
} else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) {
|
|
|
|
ql_dbg(ql_dbg_vport, vha, 0x10c5,
|
|
|
|
"%s: Failed to complete IOCB -- completion status (%x) vpidx %x\n",
|
|
|
|
sp->name, le16_to_cpu(vce->comp_status),
|
|
|
|
le16_to_cpu(vce->vp_idx_failed));
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
} else {
|
|
|
|
ql_dbg(ql_dbg_vport, vha, 0x10c6,
|
|
|
|
"Done %s.\n", __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
sp->rc = rval;
|
|
|
|
sp->done(sp, rval);
|
|
|
|
}
|
|
|
|
|
2019-04-05 03:44:44 +08:00
|
|
|
/* Process a single response queue entry. */
|
|
|
|
static void qla2x00_process_response_entry(struct scsi_qla_host *vha,
|
|
|
|
struct rsp_que *rsp,
|
|
|
|
sts_entry_t *pkt)
|
|
|
|
{
|
|
|
|
sts21_entry_t *sts21_entry;
|
|
|
|
sts22_entry_t *sts22_entry;
|
|
|
|
uint16_t handle_cnt;
|
|
|
|
uint16_t cnt;
|
|
|
|
|
|
|
|
switch (pkt->entry_type) {
|
|
|
|
case STATUS_TYPE:
|
|
|
|
qla2x00_status_entry(vha, rsp, pkt);
|
|
|
|
break;
|
|
|
|
case STATUS_TYPE_21:
|
|
|
|
sts21_entry = (sts21_entry_t *)pkt;
|
|
|
|
handle_cnt = sts21_entry->handle_count;
|
|
|
|
for (cnt = 0; cnt < handle_cnt; cnt++)
|
|
|
|
qla2x00_process_completed_request(vha, rsp->req,
|
|
|
|
sts21_entry->handle[cnt]);
|
|
|
|
break;
|
|
|
|
case STATUS_TYPE_22:
|
|
|
|
sts22_entry = (sts22_entry_t *)pkt;
|
|
|
|
handle_cnt = sts22_entry->handle_count;
|
|
|
|
for (cnt = 0; cnt < handle_cnt; cnt++)
|
|
|
|
qla2x00_process_completed_request(vha, rsp->req,
|
|
|
|
sts22_entry->handle[cnt]);
|
|
|
|
break;
|
|
|
|
case STATUS_CONT_TYPE:
|
|
|
|
qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
|
|
|
|
break;
|
|
|
|
case MBX_IOCB_TYPE:
|
|
|
|
qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
|
|
|
|
break;
|
|
|
|
case CT_IOCB_TYPE:
|
|
|
|
qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Type Not Supported. */
|
|
|
|
ql_log(ql_log_warn, vha, 0x504a,
|
|
|
|
"Received unknown response pkt type %x entry status=%x.\n",
|
|
|
|
pkt->entry_type, pkt->entry_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2x00_process_response_queue() - Process response queue entries.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @rsp: response queue
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
void
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_process_response_queue(struct rsp_que *rsp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-12-10 08:45:39 +08:00
|
|
|
struct scsi_qla_host *vha;
|
|
|
|
struct qla_hw_data *ha = rsp->hw;
|
2005-07-07 01:30:26 +08:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-17 06:20:36 +08:00
|
|
|
sts_entry_t *pkt;
|
2008-12-10 08:45:39 +08:00
|
|
|
|
2009-04-07 13:33:40 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
if (!vha->flags.online)
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
|
|
|
|
pkt = (sts_entry_t *)rsp->ring_ptr;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp->ring_index++;
|
|
|
|
if (rsp->ring_index == rsp->length) {
|
|
|
|
rsp->ring_index = 0;
|
|
|
|
rsp->ring_ptr = rsp->ring;
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp->ring_ptr++;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->entry_status != 0) {
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_error_entry(vha, rsp, pkt);
|
2005-04-17 06:20:36 +08:00
|
|
|
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
|
|
|
|
wmb();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-04-05 03:44:44 +08:00
|
|
|
qla2x00_process_response_entry(vha, rsp, pkt);
|
2005-04-17 06:20:36 +08:00
|
|
|
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
|
|
|
|
wmb();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust ring index */
|
2008-11-07 02:40:51 +08:00
|
|
|
WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-01-18 01:02:07 +08:00
|
|
|
static inline void
|
2010-07-23 18:28:27 +08:00
|
|
|
qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
|
2012-02-10 03:15:36 +08:00
|
|
|
uint32_t sense_len, struct rsp_que *rsp, int res)
|
2008-01-18 01:02:07 +08:00
|
|
|
{
|
2017-01-20 14:28:04 +08:00
|
|
|
struct scsi_qla_host *vha = sp->vha;
|
2012-02-10 03:15:36 +08:00
|
|
|
struct scsi_cmnd *cp = GET_CMD_SP(sp);
|
|
|
|
uint32_t track_sense_len;
|
2008-01-18 01:02:07 +08:00
|
|
|
|
|
|
|
if (sense_len >= SCSI_SENSE_BUFFERSIZE)
|
|
|
|
sense_len = SCSI_SENSE_BUFFERSIZE;
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
SET_CMD_SENSE_LEN(sp, sense_len);
|
|
|
|
SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
|
|
|
|
track_sense_len = sense_len;
|
|
|
|
|
|
|
|
if (sense_len > par_sense_len)
|
2010-07-23 18:28:27 +08:00
|
|
|
sense_len = par_sense_len;
|
2008-01-18 01:02:07 +08:00
|
|
|
|
|
|
|
memcpy(cp->sense_buffer, sense_data, sense_len);
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
|
|
|
|
track_sense_len -= sense_len;
|
|
|
|
SET_CMD_SENSE_LEN(sp, track_sense_len);
|
|
|
|
|
|
|
|
if (track_sense_len != 0) {
|
2009-04-07 13:33:40 +08:00
|
|
|
rsp->status_srb = sp;
|
2012-02-10 03:15:36 +08:00
|
|
|
cp->result = res;
|
|
|
|
}
|
2008-01-18 01:02:07 +08:00
|
|
|
|
2011-11-19 01:03:07 +08:00
|
|
|
if (sense_len) {
|
|
|
|
ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
|
2014-06-25 21:27:36 +08:00
|
|
|
"Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->vha->host_no, cp->device->id, cp->device->lun,
|
2011-11-19 01:03:07 +08:00
|
|
|
cp);
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
|
|
|
|
cp->sense_buffer, sense_len);
|
2011-11-19 01:03:07 +08:00
|
|
|
}
|
2008-01-18 01:02:07 +08:00
|
|
|
}
|
|
|
|
|
2010-05-05 06:01:30 +08:00
|
|
|
struct scsi_dif_tuple {
|
|
|
|
__be16 guard; /* Checksum */
|
2012-08-23 02:20:58 +08:00
|
|
|
__be16 app_tag; /* APPL identifier */
|
2010-05-05 06:01:30 +08:00
|
|
|
__be32 ref_tag; /* Target LBA or indirect LBA */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Checks the guard or meta-data for the type of error
|
|
|
|
* detected by the HBA. In case of errors, we set the
|
|
|
|
* ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
|
|
|
|
* to indicate to the kernel that the HBA detected error.
|
|
|
|
*/
|
2011-08-17 02:29:22 +08:00
|
|
|
static inline int
|
2010-05-05 06:01:30 +08:00
|
|
|
qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
|
|
|
|
{
|
2017-01-20 14:28:04 +08:00
|
|
|
struct scsi_qla_host *vha = sp->vha;
|
2012-02-10 03:15:36 +08:00
|
|
|
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
|
2011-08-17 02:29:22 +08:00
|
|
|
uint8_t *ap = &sts24->data[12];
|
|
|
|
uint8_t *ep = &sts24->data[20];
|
2010-05-05 06:01:30 +08:00
|
|
|
uint32_t e_ref_tag, a_ref_tag;
|
|
|
|
uint16_t e_app_tag, a_app_tag;
|
|
|
|
uint16_t e_guard, a_guard;
|
|
|
|
|
2011-08-17 02:29:22 +08:00
|
|
|
/*
|
|
|
|
* swab32 of the "data" field in the beginning of qla2x00_status_entry()
|
|
|
|
* would make guard field appear at offset 2
|
|
|
|
*/
|
|
|
|
a_guard = le16_to_cpu(*(uint16_t *)(ap + 2));
|
|
|
|
a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0));
|
|
|
|
a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4));
|
|
|
|
e_guard = le16_to_cpu(*(uint16_t *)(ep + 2));
|
|
|
|
e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0));
|
|
|
|
e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4));
|
2010-05-05 06:01:30 +08:00
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3023,
|
|
|
|
"iocb(s) %p Returned STATUS.\n", sts24);
|
2010-05-05 06:01:30 +08:00
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3024,
|
|
|
|
"DIF ERROR in cmd 0x%x lba 0x%llx act ref"
|
2010-05-05 06:01:30 +08:00
|
|
|
" tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
|
2011-07-15 03:00:13 +08:00
|
|
|
" tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
|
2010-05-05 06:01:30 +08:00
|
|
|
cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
|
2011-07-15 03:00:13 +08:00
|
|
|
a_app_tag, e_app_tag, a_guard, e_guard);
|
2010-05-05 06:01:30 +08:00
|
|
|
|
2011-08-17 02:29:22 +08:00
|
|
|
/*
|
|
|
|
* Ignore sector if:
|
|
|
|
* For type 3: ref & app tag is all 'f's
|
|
|
|
* For type 0,1,2: app tag is all 'f's
|
|
|
|
*/
|
2017-06-30 02:31:12 +08:00
|
|
|
if ((a_app_tag == T10_PI_APP_ESCAPE) &&
|
2011-08-17 02:29:22 +08:00
|
|
|
((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) ||
|
2017-06-30 02:31:12 +08:00
|
|
|
(a_ref_tag == T10_PI_REF_ESCAPE))) {
|
2011-08-17 02:29:22 +08:00
|
|
|
uint32_t blocks_done, resid;
|
|
|
|
sector_t lba_s = scsi_get_lba(cmd);
|
|
|
|
|
|
|
|
/* 2TB boundary case covered automatically with this */
|
|
|
|
blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
|
|
|
|
|
|
|
|
resid = scsi_bufflen(cmd) - (blocks_done *
|
|
|
|
cmd->device->sector_size);
|
|
|
|
|
|
|
|
scsi_set_resid(cmd, resid);
|
|
|
|
cmd->result = DID_OK << 16;
|
|
|
|
|
|
|
|
/* Update protection tag */
|
|
|
|
if (scsi_prot_sg_count(cmd)) {
|
|
|
|
uint32_t i, j = 0, k = 0, num_ent;
|
|
|
|
struct scatterlist *sg;
|
2016-09-12 01:35:40 +08:00
|
|
|
struct t10_pi_tuple *spt;
|
2011-08-17 02:29:22 +08:00
|
|
|
|
|
|
|
/* Patch the corresponding protection tags */
|
|
|
|
scsi_for_each_prot_sg(cmd, sg,
|
|
|
|
scsi_prot_sg_count(cmd), i) {
|
|
|
|
num_ent = sg_dma_len(sg) / 8;
|
|
|
|
if (k + num_ent < blocks_done) {
|
|
|
|
k += num_ent;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
j = blocks_done - k - 1;
|
|
|
|
k = blocks_done;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k != blocks_done) {
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x302f,
|
2011-09-24 06:40:50 +08:00
|
|
|
"unexpected tag values tag:lba=%x:%llx)\n",
|
|
|
|
e_ref_tag, (unsigned long long)lba_s);
|
2011-08-17 02:29:22 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
spt = page_address(sg_page(sg)) + sg->offset;
|
|
|
|
spt += j;
|
|
|
|
|
2017-06-30 02:31:12 +08:00
|
|
|
spt->app_tag = T10_PI_APP_ESCAPE;
|
2011-08-17 02:29:22 +08:00
|
|
|
if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
|
2017-06-30 02:31:12 +08:00
|
|
|
spt->ref_tag = T10_PI_REF_ESCAPE;
|
2011-08-17 02:29:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-05 06:01:30 +08:00
|
|
|
/* check guard */
|
|
|
|
if (e_guard != a_guard) {
|
|
|
|
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
|
|
|
0x10, 0x1);
|
|
|
|
set_driver_byte(cmd, DRIVER_SENSE);
|
|
|
|
set_host_byte(cmd, DID_ABORT);
|
2018-04-09 20:39:22 +08:00
|
|
|
cmd->result |= SAM_STAT_CHECK_CONDITION;
|
2011-08-17 02:29:22 +08:00
|
|
|
return 1;
|
2010-05-05 06:01:30 +08:00
|
|
|
}
|
|
|
|
|
2011-08-17 02:29:23 +08:00
|
|
|
/* check ref tag */
|
|
|
|
if (e_ref_tag != a_ref_tag) {
|
2010-05-05 06:01:30 +08:00
|
|
|
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
2011-08-17 02:29:23 +08:00
|
|
|
0x10, 0x3);
|
2010-05-05 06:01:30 +08:00
|
|
|
set_driver_byte(cmd, DRIVER_SENSE);
|
|
|
|
set_host_byte(cmd, DID_ABORT);
|
2018-04-09 20:39:22 +08:00
|
|
|
cmd->result |= SAM_STAT_CHECK_CONDITION;
|
2011-08-17 02:29:22 +08:00
|
|
|
return 1;
|
2010-05-05 06:01:30 +08:00
|
|
|
}
|
|
|
|
|
2011-08-17 02:29:23 +08:00
|
|
|
/* check appl tag */
|
|
|
|
if (e_app_tag != a_app_tag) {
|
2010-05-05 06:01:30 +08:00
|
|
|
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
2011-08-17 02:29:23 +08:00
|
|
|
0x10, 0x2);
|
2010-05-05 06:01:30 +08:00
|
|
|
set_driver_byte(cmd, DRIVER_SENSE);
|
|
|
|
set_host_byte(cmd, DID_ABORT);
|
2018-04-09 20:39:22 +08:00
|
|
|
cmd->result |= SAM_STAT_CHECK_CONDITION;
|
2011-08-17 02:29:22 +08:00
|
|
|
return 1;
|
2010-05-05 06:01:30 +08:00
|
|
|
}
|
2011-08-17 02:29:23 +08:00
|
|
|
|
2011-08-17 02:29:22 +08:00
|
|
|
return 1;
|
2010-05-05 06:01:30 +08:00
|
|
|
}
|
|
|
|
|
2012-08-23 02:21:01 +08:00
|
|
|
static void
|
|
|
|
qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
|
|
|
|
struct req_que *req, uint32_t index)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
srb_t *sp;
|
|
|
|
uint16_t comp_status;
|
|
|
|
uint16_t scsi_status;
|
|
|
|
uint16_t thread_id;
|
|
|
|
uint32_t rval = EXT_STATUS_OK;
|
2016-11-17 17:31:19 +08:00
|
|
|
struct bsg_job *bsg_job = NULL;
|
2016-11-17 17:31:12 +08:00
|
|
|
struct fc_bsg_request *bsg_request;
|
|
|
|
struct fc_bsg_reply *bsg_reply;
|
2012-08-23 02:21:01 +08:00
|
|
|
sts_entry_t *sts;
|
|
|
|
struct sts_entry_24xx *sts24;
|
2019-04-12 05:53:17 +08:00
|
|
|
|
2012-08-23 02:21:01 +08:00
|
|
|
sts = (sts_entry_t *) pkt;
|
|
|
|
sts24 = (struct sts_entry_24xx *) pkt;
|
|
|
|
|
|
|
|
/* Validate handle. */
|
2013-01-30 16:34:37 +08:00
|
|
|
if (index >= req->num_outstanding_cmds) {
|
2012-08-23 02:21:01 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x70af,
|
|
|
|
"Invalid SCSI completion handle 0x%x.\n", index);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp = req->outstanding_cmds[index];
|
2016-11-17 17:31:12 +08:00
|
|
|
if (!sp) {
|
2012-08-23 02:21:01 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x70b0,
|
|
|
|
"Req:%d: Invalid ISP SCSI completion handle(0x%x)\n",
|
|
|
|
req->id, index);
|
|
|
|
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-17 17:31:12 +08:00
|
|
|
/* Free outstanding command slot. */
|
|
|
|
req->outstanding_cmds[index] = NULL;
|
|
|
|
bsg_job = sp->u.bsg_job;
|
|
|
|
bsg_request = bsg_job->request;
|
|
|
|
bsg_reply = bsg_job->reply;
|
|
|
|
|
2012-08-23 02:21:01 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
|
|
|
comp_status = le16_to_cpu(sts24->comp_status);
|
|
|
|
scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
|
|
|
|
} else {
|
|
|
|
comp_status = le16_to_cpu(sts->comp_status);
|
|
|
|
scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
|
|
|
|
}
|
|
|
|
|
2016-11-17 17:31:12 +08:00
|
|
|
thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
2012-08-23 02:21:01 +08:00
|
|
|
switch (comp_status) {
|
|
|
|
case CS_COMPLETE:
|
|
|
|
if (scsi_status == 0) {
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len =
|
2012-08-23 02:21:01 +08:00
|
|
|
bsg_job->reply_payload.payload_len;
|
2013-08-27 13:37:40 +08:00
|
|
|
vha->qla_stats.input_bytes +=
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len;
|
2013-08-27 13:37:40 +08:00
|
|
|
vha->qla_stats.input_requests++;
|
2012-08-23 02:21:01 +08:00
|
|
|
rval = EXT_STATUS_OK;
|
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
case CS_DATA_OVERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b1,
|
2017-04-01 05:37:04 +08:00
|
|
|
"Command completed with data overrun thread_id=%d\n",
|
2012-08-23 02:21:01 +08:00
|
|
|
thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_OVERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_DATA_UNDERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b2,
|
2017-04-01 05:37:04 +08:00
|
|
|
"Command completed with data underrun thread_id=%d\n",
|
2012-08-23 02:21:01 +08:00
|
|
|
thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_UNDERRUN;
|
|
|
|
break;
|
|
|
|
case CS_BIDIR_RD_OVERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b3,
|
|
|
|
"Command completed with read data overrun thread_id=%d\n",
|
|
|
|
thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_OVERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_RD_WR_OVERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b4,
|
|
|
|
"Command completed with read and write data overrun "
|
|
|
|
"thread_id=%d\n", thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_OVERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b5,
|
|
|
|
"Command completed with read data over and write data "
|
|
|
|
"underrun thread_id=%d\n", thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_OVERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_RD_UNDERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b6,
|
2017-04-01 05:37:04 +08:00
|
|
|
"Command completed with read data underrun "
|
2012-08-23 02:21:01 +08:00
|
|
|
"thread_id=%d\n", thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_UNDERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b7,
|
|
|
|
"Command completed with read data under and write data "
|
|
|
|
"overrun thread_id=%d\n", thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_UNDERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_RD_WR_UNDERRUN:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b8,
|
|
|
|
"Command completed with read and write data underrun "
|
|
|
|
"thread_id=%d\n", thread_id);
|
|
|
|
rval = EXT_STATUS_DATA_UNDERRUN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_BIDIR_DMA:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70b9,
|
|
|
|
"Command completed with data DMA error thread_id=%d\n",
|
|
|
|
thread_id);
|
|
|
|
rval = EXT_STATUS_DMA_ERR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_TIMEOUT:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70ba,
|
|
|
|
"Command completed with timeout thread_id=%d\n",
|
|
|
|
thread_id);
|
|
|
|
rval = EXT_STATUS_TIMEOUT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ql_dbg(ql_dbg_user, vha, 0x70bb,
|
|
|
|
"Command completed with completion status=0x%x "
|
|
|
|
"thread_id=%d\n", comp_status, thread_id);
|
|
|
|
rval = EXT_STATUS_ERR;
|
|
|
|
break;
|
|
|
|
}
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_payload_rcv_len = 0;
|
2012-08-23 02:21:01 +08:00
|
|
|
|
|
|
|
done:
|
|
|
|
/* Return the vendor specific reply to API */
|
2016-11-17 17:31:12 +08:00
|
|
|
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
|
2012-08-23 02:21:01 +08:00
|
|
|
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
|
|
|
/* Always return DID_OK, bsg will send the vendor specific response
|
|
|
|
* in this case only */
|
2018-04-09 20:24:23 +08:00
|
|
|
sp->done(sp, DID_OK << 16);
|
2012-08-23 02:21:01 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2x00_status_entry() - Process a Status IOCB entry.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
|
|
|
* @rsp: response queue
|
2005-04-17 06:20:36 +08:00
|
|
|
* @pkt: Entry pointer
|
|
|
|
*/
|
|
|
|
static void
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
srb_t *sp;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
struct scsi_cmnd *cp;
|
2005-07-07 01:31:27 +08:00
|
|
|
sts_entry_t *sts;
|
|
|
|
struct sts_entry_24xx *sts24;
|
2005-04-17 06:20:36 +08:00
|
|
|
uint16_t comp_status;
|
|
|
|
uint16_t scsi_status;
|
2010-05-05 06:01:27 +08:00
|
|
|
uint16_t ox_id;
|
2005-04-17 06:20:36 +08:00
|
|
|
uint8_t lscsi_status;
|
|
|
|
int32_t resid;
|
2010-07-23 18:28:27 +08:00
|
|
|
uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
|
|
|
|
fw_resid_len;
|
2005-07-07 01:31:27 +08:00
|
|
|
uint8_t *rsp_info, *sense_data;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2009-04-07 13:33:40 +08:00
|
|
|
uint32_t handle;
|
|
|
|
uint16_t que;
|
|
|
|
struct req_que *req;
|
2010-05-05 06:01:27 +08:00
|
|
|
int logit = 1;
|
2012-02-10 03:15:36 +08:00
|
|
|
int res = 0;
|
2012-08-23 02:21:01 +08:00
|
|
|
uint16_t state_flags = 0;
|
2014-09-25 17:16:59 +08:00
|
|
|
uint16_t retry_delay = 0;
|
2005-07-07 01:31:27 +08:00
|
|
|
|
|
|
|
sts = (sts_entry_t *) pkt;
|
|
|
|
sts24 = (struct sts_entry_24xx *) pkt;
|
2007-07-20 06:05:56 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
2005-07-07 01:31:27 +08:00
|
|
|
comp_status = le16_to_cpu(sts24->comp_status);
|
|
|
|
scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
|
2012-08-23 02:21:01 +08:00
|
|
|
state_flags = le16_to_cpu(sts24->state_flags);
|
2005-07-07 01:31:27 +08:00
|
|
|
} else {
|
|
|
|
comp_status = le16_to_cpu(sts->comp_status);
|
|
|
|
scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
|
|
|
|
}
|
2009-04-07 13:33:40 +08:00
|
|
|
handle = (uint32_t) LSW(sts->handle);
|
|
|
|
que = MSW(sts->handle);
|
|
|
|
req = ha->req_q_map[que];
|
2010-04-13 08:59:55 +08:00
|
|
|
|
2013-10-03 15:21:13 +08:00
|
|
|
/* Check for invalid queue pointer */
|
|
|
|
if (req == NULL ||
|
|
|
|
que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
|
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3059,
|
|
|
|
"Invalid status handle (0x%x): Bad req pointer. req=%p, "
|
|
|
|
"que=%u.\n", sts->handle, req, que);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Validate handle. */
|
2015-08-05 01:37:57 +08:00
|
|
|
if (handle < req->num_outstanding_cmds) {
|
2009-04-07 13:33:40 +08:00
|
|
|
sp = req->outstanding_cmds[handle];
|
2015-08-05 01:37:57 +08:00
|
|
|
if (!sp) {
|
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3075,
|
|
|
|
"%s(%ld): Already returned command for status handle (0x%x).\n",
|
|
|
|
__func__, vha->host_no, sts->handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3017,
|
2015-08-05 01:37:57 +08:00
|
|
|
"Invalid status handle, out of range (0x%x).\n",
|
|
|
|
sts->handle);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-12 04:54:07 +08:00
|
|
|
if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
|
|
|
|
if (IS_P3P_TYPE(ha))
|
|
|
|
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
|
|
|
qla2xxx_wake_dpc(vha);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-23 02:21:01 +08:00
|
|
|
|
2017-06-14 11:47:16 +08:00
|
|
|
if (sp->cmd_type != TYPE_SRB) {
|
|
|
|
req->outstanding_cmds[handle] = NULL;
|
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3015,
|
|
|
|
"Unknown sp->cmd_type %x %p).\n",
|
|
|
|
sp->cmd_type, sp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-22 04:48:42 +08:00
|
|
|
/* NVME completion. */
|
|
|
|
if (sp->type == SRB_NVME_CMD) {
|
2018-03-21 14:09:39 +08:00
|
|
|
req->outstanding_cmds[handle] = NULL;
|
|
|
|
qla24xx_nvme_iocb_entry(vha, req, pkt, sp);
|
2017-06-22 04:48:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-23 02:21:01 +08:00
|
|
|
if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) {
|
|
|
|
qla25xx_process_bidir_status_iocb(vha, pkt, req, handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-26 17:15:17 +08:00
|
|
|
/* Task Management completion. */
|
|
|
|
if (sp->type == SRB_TM_CMD) {
|
|
|
|
qla24xx_tm_iocb_entry(vha, req, pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-23 02:21:01 +08:00
|
|
|
/* Fast path completion. */
|
|
|
|
if (comp_status == CS_COMPLETE && scsi_status == 0) {
|
|
|
|
qla2x00_process_completed_request(vha, req, handle);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
req->outstanding_cmds[handle] = NULL;
|
2012-02-10 03:15:36 +08:00
|
|
|
cp = GET_CMD_SP(sp);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (cp == NULL) {
|
2011-11-19 01:03:07 +08:00
|
|
|
ql_dbg(ql_dbg_io, vha, 0x3018,
|
2011-07-15 03:00:13 +08:00
|
|
|
"Command already returned (0x%x/%p).\n",
|
|
|
|
sts->handle, sp);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-28 20:21:23 +08:00
|
|
|
lscsi_status = scsi_status & STATUS_MASK;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-18 04:06:53 +08:00
|
|
|
fcport = sp->fcport;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-05-05 06:01:27 +08:00
|
|
|
ox_id = 0;
|
2010-07-23 18:28:27 +08:00
|
|
|
sense_len = par_sense_len = rsp_info_len = resid_len =
|
|
|
|
fw_resid_len = 0;
|
2007-07-20 06:05:56 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
2009-10-14 06:16:52 +08:00
|
|
|
if (scsi_status & SS_SENSE_LEN_VALID)
|
|
|
|
sense_len = le32_to_cpu(sts24->sense_len);
|
|
|
|
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
|
|
|
|
rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
|
|
|
|
if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
|
|
|
|
resid_len = le32_to_cpu(sts24->rsp_residual_count);
|
|
|
|
if (comp_status == CS_DATA_UNDERRUN)
|
|
|
|
fw_resid_len = le32_to_cpu(sts24->residual_len);
|
2005-07-07 01:31:27 +08:00
|
|
|
rsp_info = sts24->data;
|
|
|
|
sense_data = sts24->data;
|
|
|
|
host_to_fcp_swap(sts24->data, sizeof(sts24->data));
|
2010-05-05 06:01:27 +08:00
|
|
|
ox_id = le16_to_cpu(sts24->ox_id);
|
2010-07-23 18:28:27 +08:00
|
|
|
par_sense_len = sizeof(sts24->data);
|
2014-09-25 17:16:59 +08:00
|
|
|
/* Valid values of the retry delay timer are 0x1-0xffef */
|
2018-06-06 23:41:42 +08:00
|
|
|
if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1) {
|
|
|
|
retry_delay = sts24->retry_delay & 0x3fff;
|
|
|
|
ql_dbg(ql_dbg_io, sp->vha, 0x3033,
|
|
|
|
"%s: scope=%#x retry_delay=%#x\n", __func__,
|
|
|
|
sts24->retry_delay >> 14, retry_delay);
|
|
|
|
}
|
2005-07-07 01:31:27 +08:00
|
|
|
} else {
|
2009-10-14 06:16:52 +08:00
|
|
|
if (scsi_status & SS_SENSE_LEN_VALID)
|
|
|
|
sense_len = le16_to_cpu(sts->req_sense_length);
|
|
|
|
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
|
|
|
|
rsp_info_len = le16_to_cpu(sts->rsp_info_len);
|
2005-07-07 01:31:27 +08:00
|
|
|
resid_len = le32_to_cpu(sts->residual_length);
|
|
|
|
rsp_info = sts->rsp_info;
|
|
|
|
sense_data = sts->req_sense_data;
|
2010-07-23 18:28:27 +08:00
|
|
|
par_sense_len = sizeof(sts->req_sense_data);
|
2005-07-07 01:31:27 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Check for any FCP transport errors. */
|
|
|
|
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
|
2005-07-07 01:31:27 +08:00
|
|
|
/* Sense data lies beyond any FCP RESPONSE data. */
|
2010-07-23 18:28:27 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
2005-07-07 01:31:27 +08:00
|
|
|
sense_data += rsp_info_len;
|
2010-07-23 18:28:27 +08:00
|
|
|
par_sense_len -= rsp_info_len;
|
|
|
|
}
|
2005-07-07 01:31:27 +08:00
|
|
|
if (rsp_info_len > 3 && rsp_info[3]) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
|
2011-07-15 03:00:13 +08:00
|
|
|
"FCP I/O protocol failure (0x%x/0x%x).\n",
|
|
|
|
rsp_info_len, rsp_info[3]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_BUS_BUSY << 16;
|
2010-05-05 06:01:27 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-29 06:06:10 +08:00
|
|
|
/* Check for overrun. */
|
|
|
|
if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
|
|
|
|
scsi_status & SS_RESIDUAL_OVER)
|
|
|
|
comp_status = CS_DATA_OVERRUN;
|
|
|
|
|
2014-09-25 17:16:59 +08:00
|
|
|
/*
|
|
|
|
* Check retry_delay_timer value if we receive a busy or
|
|
|
|
* queue full.
|
|
|
|
*/
|
|
|
|
if (lscsi_status == SAM_STAT_TASK_SET_FULL ||
|
|
|
|
lscsi_status == SAM_STAT_BUSY)
|
|
|
|
qla2x00_set_retry_delay_timestamp(fcport, retry_delay);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Based on Host and scsi status generate status code for Linux
|
|
|
|
*/
|
|
|
|
switch (comp_status) {
|
|
|
|
case CS_COMPLETE:
|
2006-10-14 00:33:39 +08:00
|
|
|
case CS_QUEUE_FULL:
|
2005-04-17 06:20:36 +08:00
|
|
|
if (scsi_status == 0) {
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_OK << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
|
2005-07-07 01:31:27 +08:00
|
|
|
resid = resid_len;
|
2007-05-26 00:55:38 +08:00
|
|
|
scsi_set_resid(cp, resid);
|
2005-12-07 02:58:06 +08:00
|
|
|
|
|
|
|
if (!lscsi_status &&
|
2007-05-26 00:55:38 +08:00
|
|
|
((unsigned)(scsi_bufflen(cp) - resid) <
|
2005-12-07 02:58:06 +08:00
|
|
|
cp->underflow)) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
|
2017-06-03 00:12:01 +08:00
|
|
|
"Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
|
2011-07-15 03:00:13 +08:00
|
|
|
resid, scsi_bufflen(cp));
|
2005-12-07 02:58:06 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16;
|
2005-12-07 02:58:06 +08:00
|
|
|
break;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_OK << 16 | lscsi_status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-10-14 00:33:39 +08:00
|
|
|
if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
|
2011-07-15 03:00:13 +08:00
|
|
|
"QUEUE FULL detected.\n");
|
2006-10-14 00:33:39 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-05-05 06:01:27 +08:00
|
|
|
logit = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (lscsi_status != SS_CHECK_CONDITION)
|
|
|
|
break;
|
|
|
|
|
2008-01-13 14:46:13 +08:00
|
|
|
memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!(scsi_status & SS_SENSE_LEN_VALID))
|
|
|
|
break;
|
|
|
|
|
2010-07-23 18:28:27 +08:00
|
|
|
qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
|
2012-02-10 03:15:36 +08:00
|
|
|
rsp, res);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_DATA_UNDERRUN:
|
2006-05-18 06:08:55 +08:00
|
|
|
/* Use F/W calculated residual length. */
|
2009-10-14 06:16:52 +08:00
|
|
|
resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
|
|
|
|
scsi_set_resid(cp, resid);
|
|
|
|
if (scsi_status & SS_RESIDUAL_UNDER) {
|
|
|
|
if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
|
2017-06-03 00:12:01 +08:00
|
|
|
"Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
|
2011-07-15 03:00:13 +08:00
|
|
|
resid, scsi_bufflen(cp));
|
2009-10-14 06:16:52 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16 | lscsi_status;
|
2011-11-19 01:02:10 +08:00
|
|
|
goto check_scsi_status;
|
2007-10-20 06:59:18 +08:00
|
|
|
}
|
2006-05-18 06:08:55 +08:00
|
|
|
|
2009-10-14 06:16:52 +08:00
|
|
|
if (!lscsi_status &&
|
|
|
|
((unsigned)(scsi_bufflen(cp) - resid) <
|
|
|
|
cp->underflow)) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
|
2017-06-03 00:12:01 +08:00
|
|
|
"Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
|
2011-07-15 03:00:13 +08:00
|
|
|
resid, scsi_bufflen(cp));
|
2006-01-14 09:04:59 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16;
|
2009-10-14 06:16:52 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-04-25 22:26:15 +08:00
|
|
|
} else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
|
|
|
|
lscsi_status != SAM_STAT_BUSY) {
|
|
|
|
/*
|
|
|
|
* scsi status of task set and busy are considered to be
|
|
|
|
* task not completed.
|
|
|
|
*/
|
|
|
|
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
|
2017-06-03 00:12:01 +08:00
|
|
|
"Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
|
|
|
|
resid, scsi_bufflen(cp));
|
2009-10-14 06:16:52 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16 | lscsi_status;
|
2010-09-04 05:57:04 +08:00
|
|
|
goto check_scsi_status;
|
2012-04-25 22:26:15 +08:00
|
|
|
} else {
|
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x3030,
|
|
|
|
"scsi_status: 0x%x, lscsi_status: 0x%x\n",
|
|
|
|
scsi_status, lscsi_status);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_OK << 16 | lscsi_status;
|
2010-05-05 06:01:27 +08:00
|
|
|
logit = 0;
|
2009-10-14 06:16:52 +08:00
|
|
|
|
2010-09-04 05:57:04 +08:00
|
|
|
check_scsi_status:
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2005-07-07 01:32:07 +08:00
|
|
|
* Check to see if SCSI Status is non zero. If so report SCSI
|
2005-04-17 06:20:36 +08:00
|
|
|
* Status.
|
|
|
|
*/
|
|
|
|
if (lscsi_status != 0) {
|
2007-01-30 02:22:27 +08:00
|
|
|
if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
|
2011-07-15 03:00:13 +08:00
|
|
|
"QUEUE FULL detected.\n");
|
2010-05-05 06:01:27 +08:00
|
|
|
logit = 1;
|
2007-01-30 02:22:27 +08:00
|
|
|
break;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
if (lscsi_status != SS_CHECK_CONDITION)
|
|
|
|
break;
|
|
|
|
|
2008-01-13 14:46:13 +08:00
|
|
|
memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!(scsi_status & SS_SENSE_LEN_VALID))
|
|
|
|
break;
|
|
|
|
|
2010-07-23 18:28:27 +08:00
|
|
|
qla2x00_handle_sense(sp, sense_data, par_sense_len,
|
2012-02-10 03:15:36 +08:00
|
|
|
sense_len, rsp, res);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_PORT_LOGGED_OUT:
|
|
|
|
case CS_PORT_CONFIG_CHG:
|
|
|
|
case CS_PORT_BUSY:
|
|
|
|
case CS_INCOMPLETE:
|
|
|
|
case CS_PORT_UNAVAILABLE:
|
2010-05-05 06:01:27 +08:00
|
|
|
case CS_TIMEOUT:
|
2010-10-16 02:27:42 +08:00
|
|
|
case CS_RESET:
|
|
|
|
|
2008-08-20 07:45:29 +08:00
|
|
|
/*
|
|
|
|
* We are going to have the fc class block the rport
|
|
|
|
* while we try to recover so instruct the mid layer
|
|
|
|
* to requeue until the class decides how to handle this.
|
|
|
|
*/
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_TRANSPORT_DISRUPTED << 16;
|
2010-05-05 06:01:27 +08:00
|
|
|
|
|
|
|
if (comp_status == CS_TIMEOUT) {
|
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
|
|
|
break;
|
|
|
|
else if ((le16_to_cpu(sts->status_flags) &
|
|
|
|
SF_LOGOUT_SENT) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-01-20 14:28:00 +08:00
|
|
|
if (atomic_read(&fcport->state) == FCS_ONLINE) {
|
|
|
|
ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
|
|
|
|
"Port to be marked lost on fcport=%02x%02x%02x, current "
|
|
|
|
"port state= %s comp_status %x.\n", fcport->d_id.b.domain,
|
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
|
|
|
port_state_str[atomic_read(&fcport->state)],
|
|
|
|
comp_status);
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
|
2017-12-29 04:33:43 +08:00
|
|
|
qlt_schedule_sess_for_deletion(fcport);
|
2017-01-20 14:28:00 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CS_ABORTED:
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_RESET << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2010-05-05 06:01:30 +08:00
|
|
|
|
|
|
|
case CS_DIF_ERROR:
|
2011-08-17 02:29:22 +08:00
|
|
|
logit = qla2x00_handle_dif_error(sp, sts24);
|
2012-08-23 02:21:32 +08:00
|
|
|
res = cp->result;
|
2010-05-05 06:01:30 +08:00
|
|
|
break;
|
2012-08-23 02:21:31 +08:00
|
|
|
|
|
|
|
case CS_TRANSPORT:
|
|
|
|
res = DID_ERROR << 16;
|
|
|
|
|
|
|
|
if (!IS_PI_SPLIT_DET_CAPABLE(ha))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (state_flags & BIT_4)
|
|
|
|
scmd_printk(KERN_WARNING, cp,
|
|
|
|
"Unsupported device '%s' found.\n",
|
|
|
|
cp->device->vendor);
|
|
|
|
break;
|
|
|
|
|
2018-12-22 01:33:45 +08:00
|
|
|
case CS_DMA:
|
|
|
|
ql_log(ql_log_info, fcport->vha, 0x3022,
|
|
|
|
"CS_DMA error: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%06x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
|
|
|
|
comp_status, scsi_status, res, vha->host_no,
|
|
|
|
cp->device->id, cp->device->lun, fcport->d_id.b24,
|
|
|
|
ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len,
|
|
|
|
resid_len, fw_resid_len, sp, cp);
|
|
|
|
ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
|
|
|
|
pkt, sizeof(*sts24));
|
|
|
|
res = DID_ERROR << 16;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
2012-02-10 03:15:36 +08:00
|
|
|
res = DID_ERROR << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-05 06:01:27 +08:00
|
|
|
out:
|
|
|
|
if (logit)
|
2012-02-10 03:15:51 +08:00
|
|
|
ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
|
2014-06-25 21:27:36 +08:00
|
|
|
"FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
|
2013-08-27 13:37:27 +08:00
|
|
|
"portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
|
2015-08-05 01:37:57 +08:00
|
|
|
"rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
|
2012-02-10 03:15:36 +08:00
|
|
|
comp_status, scsi_status, res, vha->host_no,
|
2011-11-19 01:03:07 +08:00
|
|
|
cp->device->id, cp->device->lun, fcport->d_id.b.domain,
|
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
|
2013-08-27 13:37:27 +08:00
|
|
|
cp->cmnd, scsi_bufflen(cp), rsp_info_len,
|
2015-08-05 01:37:57 +08:00
|
|
|
resid_len, fw_resid_len, sp, cp);
|
2010-05-05 06:01:27 +08:00
|
|
|
|
2009-04-07 13:33:40 +08:00
|
|
|
if (rsp->status_srb == NULL)
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, res);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_status_cont_entry() - Process a Status Continuations entry.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @rsp: response queue
|
2005-04-17 06:20:36 +08:00
|
|
|
* @pkt: Entry pointer
|
|
|
|
*
|
|
|
|
* Extended sense data.
|
|
|
|
*/
|
|
|
|
static void
|
2009-04-07 13:33:40 +08:00
|
|
|
qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-02-10 03:15:36 +08:00
|
|
|
uint8_t sense_sz = 0;
|
2009-04-07 13:33:40 +08:00
|
|
|
struct qla_hw_data *ha = rsp->hw;
|
2011-07-15 03:00:13 +08:00
|
|
|
struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
|
2012-02-10 03:15:36 +08:00
|
|
|
srb_t *sp = rsp->status_srb;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct scsi_cmnd *cp;
|
2012-02-10 03:15:36 +08:00
|
|
|
uint32_t sense_len;
|
|
|
|
uint8_t *sense_ptr;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
if (!sp || !GET_CMD_SENSE_LEN(sp))
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
sense_len = GET_CMD_SENSE_LEN(sp);
|
|
|
|
sense_ptr = GET_CMD_SENSE_PTR(sp);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
cp = GET_CMD_SP(sp);
|
|
|
|
if (cp == NULL) {
|
|
|
|
ql_log(ql_log_warn, vha, 0x3025,
|
|
|
|
"cmd is NULL: already returned to OS (sp=%p).\n", sp);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
rsp->status_srb = NULL;
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
if (sense_len > sizeof(pkt->data))
|
|
|
|
sense_sz = sizeof(pkt->data);
|
|
|
|
else
|
|
|
|
sense_sz = sense_len;
|
2011-11-19 01:03:08 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
/* Move sense data. */
|
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
|
|
|
host_to_fcp_swap(pkt->data, sizeof(pkt->data));
|
|
|
|
memcpy(sense_ptr, pkt->data, sense_sz);
|
|
|
|
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
|
|
|
|
sense_ptr, sense_sz);
|
2011-11-19 01:03:08 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
sense_len -= sense_sz;
|
|
|
|
sense_ptr += sense_sz;
|
2011-11-19 01:03:08 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
SET_CMD_SENSE_PTR(sp, sense_ptr);
|
|
|
|
SET_CMD_SENSE_LEN(sp, sense_len);
|
|
|
|
|
|
|
|
/* Place command on done queue. */
|
|
|
|
if (sense_len == 0) {
|
|
|
|
rsp->status_srb = NULL;
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, cp->result);
|
2011-11-19 01:03:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* qla2x00_error_entry() - Process an error entry.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
|
|
|
* @rsp: response queue
|
2005-04-17 06:20:36 +08:00
|
|
|
* @pkt: Entry pointer
|
2017-06-14 11:47:16 +08:00
|
|
|
* return : 1=allow further error analysis. 0=no additional error analysis.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2017-06-14 11:47:16 +08:00
|
|
|
static int
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
srb_t *sp;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2011-11-19 01:03:08 +08:00
|
|
|
const char func[] = "ERROR-IOCB";
|
2009-04-07 13:33:40 +08:00
|
|
|
uint16_t que = MSW(pkt->handle);
|
2012-02-10 03:16:01 +08:00
|
|
|
struct req_que *req = NULL;
|
2012-02-10 03:15:36 +08:00
|
|
|
int res = DID_ERROR << 16;
|
2011-07-15 03:00:13 +08:00
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x502a,
|
2017-06-14 11:47:17 +08:00
|
|
|
"iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
|
|
|
|
pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id);
|
2012-02-10 03:15:36 +08:00
|
|
|
|
2012-02-10 03:16:01 +08:00
|
|
|
if (que >= ha->max_req_queues || !ha->req_q_map[que])
|
|
|
|
goto fatal;
|
|
|
|
|
|
|
|
req = ha->req_q_map[que];
|
|
|
|
|
2012-02-10 03:15:36 +08:00
|
|
|
if (pkt->entry_status & RF_BUSY)
|
|
|
|
res = DID_BUS_BUSY << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-06-14 11:47:16 +08:00
|
|
|
if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE)
|
|
|
|
return 0;
|
2016-12-24 10:06:13 +08:00
|
|
|
|
2017-06-14 11:47:16 +08:00
|
|
|
switch (pkt->entry_type) {
|
|
|
|
case NOTIFY_ACK_TYPE:
|
|
|
|
case STATUS_TYPE:
|
|
|
|
case STATUS_CONT_TYPE:
|
|
|
|
case LOGINOUT_PORT_IOCB_TYPE:
|
|
|
|
case CT_IOCB_TYPE:
|
|
|
|
case ELS_IOCB_TYPE:
|
|
|
|
case ABORT_IOCB_TYPE:
|
|
|
|
case MBX_IOCB_TYPE:
|
2018-09-12 01:18:16 +08:00
|
|
|
default:
|
2017-06-14 11:47:16 +08:00
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (sp) {
|
|
|
|
sp->done(sp, res);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ABTS_RESP_24XX:
|
|
|
|
case CTIO_TYPE7:
|
|
|
|
case CTIO_CRC2:
|
|
|
|
return 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2012-02-10 03:16:01 +08:00
|
|
|
fatal:
|
|
|
|
ql_log(ql_log_warn, vha, 0x5030,
|
2015-08-05 01:37:58 +08:00
|
|
|
"Error entry - invalid handle/queue (%04x).\n", que);
|
2017-06-14 11:47:16 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
/**
|
|
|
|
* qla24xx_mbx_completion() - Process mailbox command completions.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
2005-07-07 01:31:27 +08:00
|
|
|
* @mb0: Mailbox0 register
|
|
|
|
*/
|
|
|
|
static void
|
2008-11-07 02:40:51 +08:00
|
|
|
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
|
2005-07-07 01:31:27 +08:00
|
|
|
{
|
|
|
|
uint16_t cnt;
|
2011-11-19 01:03:09 +08:00
|
|
|
uint32_t mboxes;
|
2005-07-07 01:31:27 +08:00
|
|
|
uint16_t __iomem *wptr;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-07 01:31:27 +08:00
|
|
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
|
|
2011-11-19 01:03:09 +08:00
|
|
|
/* Read all mbox registers? */
|
2018-01-26 00:24:29 +08:00
|
|
|
WARN_ON_ONCE(ha->mbx_count > 32);
|
|
|
|
mboxes = (1ULL << ha->mbx_count) - 1;
|
2011-11-19 01:03:09 +08:00
|
|
|
if (!ha->mcp)
|
2012-11-21 15:40:42 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
|
2011-11-19 01:03:09 +08:00
|
|
|
else
|
|
|
|
mboxes = ha->mcp->in_mb;
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
/* Load return mailbox registers. */
|
|
|
|
ha->flags.mbox_int = 1;
|
|
|
|
ha->mailbox_out[0] = mb0;
|
2011-11-19 01:03:09 +08:00
|
|
|
mboxes >>= 1;
|
2005-07-07 01:31:27 +08:00
|
|
|
wptr = (uint16_t __iomem *)®->mailbox1;
|
|
|
|
|
|
|
|
for (cnt = 1; cnt < ha->mbx_count; cnt++) {
|
2011-11-19 01:03:09 +08:00
|
|
|
if (mboxes & BIT_0)
|
|
|
|
ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
|
|
|
|
|
|
|
|
mboxes >>= 1;
|
2005-07-07 01:31:27 +08:00
|
|
|
wptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-26 17:15:18 +08:00
|
|
|
static void
|
|
|
|
qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|
|
|
struct abort_entry_24xx *pkt)
|
|
|
|
{
|
|
|
|
const char func[] = "ABT_IOCB";
|
|
|
|
srb_t *sp;
|
|
|
|
struct srb_iocb *abt;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
abt = &sp->u.iocb_cmd;
|
2017-03-16 00:48:52 +08:00
|
|
|
abt->u.abt.comp_status = le16_to_cpu(pkt->nport_handle);
|
2017-01-20 14:28:04 +08:00
|
|
|
sp->done(sp, 0);
|
2014-02-26 17:15:18 +08:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:32:24 +08:00
|
|
|
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
|
|
|
|
struct pt_ls4_request *pkt, struct req_que *req)
|
2017-06-22 04:48:43 +08:00
|
|
|
{
|
|
|
|
srb_t *sp;
|
|
|
|
const char func[] = "LS4_IOCB";
|
|
|
|
uint16_t comp_status;
|
|
|
|
|
|
|
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
|
|
|
if (!sp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
comp_status = le16_to_cpu(pkt->status);
|
|
|
|
sp->done(sp, comp_status);
|
|
|
|
}
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
/**
|
|
|
|
* qla24xx_process_response_queue() - Process response queue entries.
|
2018-01-24 08:33:51 +08:00
|
|
|
* @vha: SCSI driver HA context
|
|
|
|
* @rsp: response queue
|
2005-07-07 01:31:27 +08:00
|
|
|
*/
|
2009-04-07 13:33:40 +08:00
|
|
|
void qla24xx_process_response_queue(struct scsi_qla_host *vha,
|
|
|
|
struct rsp_que *rsp)
|
2005-07-07 01:31:27 +08:00
|
|
|
{
|
|
|
|
struct sts_entry_24xx *pkt;
|
2010-04-13 08:59:55 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-07 01:31:27 +08:00
|
|
|
|
2017-03-16 00:48:55 +08:00
|
|
|
if (!ha->flags.fw_started)
|
2005-07-07 01:31:27 +08:00
|
|
|
return;
|
|
|
|
|
2017-06-14 11:47:18 +08:00
|
|
|
if (rsp->qpair->cpuid != smp_processor_id())
|
|
|
|
qla_cpu_update(rsp->qpair, smp_processor_id());
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
|
|
|
|
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
|
2005-07-07 01:31:27 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp->ring_index++;
|
|
|
|
if (rsp->ring_index == rsp->length) {
|
|
|
|
rsp->ring_index = 0;
|
|
|
|
rsp->ring_ptr = rsp->ring;
|
2005-07-07 01:31:27 +08:00
|
|
|
} else {
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp->ring_ptr++;
|
2005-07-07 01:31:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt->entry_status != 0) {
|
2017-06-14 11:47:16 +08:00
|
|
|
if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
|
2014-04-12 04:54:43 +08:00
|
|
|
goto process_err;
|
2012-05-16 02:34:28 +08:00
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
|
|
|
|
wmb();
|
|
|
|
continue;
|
|
|
|
}
|
2014-04-12 04:54:43 +08:00
|
|
|
process_err:
|
2005-07-07 01:31:27 +08:00
|
|
|
|
|
|
|
switch (pkt->entry_type) {
|
|
|
|
case STATUS_TYPE:
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_status_entry(vha, rsp, pkt);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
|
|
|
case STATUS_CONT_TYPE:
|
2009-04-07 13:33:40 +08:00
|
|
|
qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
2007-07-06 04:16:51 +08:00
|
|
|
case VP_RPT_ID_IOCB_TYPE:
|
2008-11-07 02:40:51 +08:00
|
|
|
qla24xx_report_id_acquisition(vha,
|
2007-07-06 04:16:51 +08:00
|
|
|
(struct vp_rpt_id_entry_24xx *)pkt);
|
|
|
|
break;
|
2009-08-21 02:06:05 +08:00
|
|
|
case LOGINOUT_PORT_IOCB_TYPE:
|
|
|
|
qla24xx_logio_entry(vha, rsp->req,
|
|
|
|
(struct logio_entry_24xx *)pkt);
|
|
|
|
break;
|
2014-04-12 04:54:43 +08:00
|
|
|
case CT_IOCB_TYPE:
|
2010-01-13 05:02:47 +08:00
|
|
|
qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
|
|
|
|
break;
|
2014-04-12 04:54:43 +08:00
|
|
|
case ELS_IOCB_TYPE:
|
2010-01-13 05:02:47 +08:00
|
|
|
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
|
|
|
|
break;
|
2012-05-16 02:34:28 +08:00
|
|
|
case ABTS_RECV_24XX:
|
2019-03-13 02:08:13 +08:00
|
|
|
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
|
|
|
|
IS_QLA28XX(ha)) {
|
2015-12-18 03:57:07 +08:00
|
|
|
/* ensure that the ATIO queue is empty */
|
2017-06-14 11:47:17 +08:00
|
|
|
qlt_handle_abts_recv(vha, rsp,
|
|
|
|
(response_t *)pkt);
|
2015-12-18 03:57:07 +08:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
qlt_24xx_process_atio_queue(vha, 1);
|
|
|
|
}
|
2017-12-08 08:02:46 +08:00
|
|
|
/* fall through */
|
2012-05-16 02:34:28 +08:00
|
|
|
case ABTS_RESP_24XX:
|
|
|
|
case CTIO_TYPE7:
|
2014-04-12 04:54:43 +08:00
|
|
|
case CTIO_CRC2:
|
2017-06-14 11:47:17 +08:00
|
|
|
qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt);
|
2012-05-16 02:34:28 +08:00
|
|
|
break;
|
2017-06-22 04:48:43 +08:00
|
|
|
case PT_LS4_REQUEST:
|
|
|
|
qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt,
|
|
|
|
rsp->req);
|
|
|
|
break;
|
2017-01-20 14:28:00 +08:00
|
|
|
case NOTIFY_ACK_TYPE:
|
|
|
|
if (pkt->handle == QLA_TGT_SKIP_HANDLE)
|
2017-06-14 11:47:17 +08:00
|
|
|
qlt_response_pkt_all_vps(vha, rsp,
|
|
|
|
(response_t *)pkt);
|
2017-01-20 14:28:00 +08:00
|
|
|
else
|
|
|
|
qla24xxx_nack_iocb_entry(vha, rsp->req,
|
|
|
|
(struct nack_to_isp *)pkt);
|
|
|
|
break;
|
2011-08-17 02:31:48 +08:00
|
|
|
case MARKER_TYPE:
|
|
|
|
/* Do nothing in this case, this check is to prevent it
|
|
|
|
* from falling into default case
|
|
|
|
*/
|
|
|
|
break;
|
2014-02-26 17:15:18 +08:00
|
|
|
case ABORT_IOCB_TYPE:
|
|
|
|
qla24xx_abort_iocb_entry(vha, rsp->req,
|
|
|
|
(struct abort_entry_24xx *)pkt);
|
|
|
|
break;
|
2017-01-20 14:28:00 +08:00
|
|
|
case MBX_IOCB_TYPE:
|
|
|
|
qla24xx_mbx_iocb_entry(vha, rsp->req,
|
|
|
|
(struct mbx_24xx_entry *)pkt);
|
|
|
|
break;
|
2017-12-29 04:33:10 +08:00
|
|
|
case VP_CTRL_IOCB_TYPE:
|
|
|
|
qla_ctrlvp_completed(vha, rsp->req,
|
|
|
|
(struct vp_ctrl_entry_24xx *)pkt);
|
|
|
|
break;
|
2005-07-07 01:31:27 +08:00
|
|
|
default:
|
|
|
|
/* Type Not Supported. */
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5042,
|
|
|
|
"Received unknown response pkt type %x "
|
2005-07-07 01:31:27 +08:00
|
|
|
"entry status=%x.\n",
|
2011-07-15 03:00:13 +08:00
|
|
|
pkt->entry_type, pkt->entry_status);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
|
|
|
|
wmb();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust ring index */
|
2013-08-27 13:37:28 +08:00
|
|
|
if (IS_P3P_TYPE(ha)) {
|
2010-04-13 08:59:55 +08:00
|
|
|
struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
|
2019-04-12 05:53:17 +08:00
|
|
|
|
2010-04-13 08:59:55 +08:00
|
|
|
WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index);
|
2017-01-20 14:28:00 +08:00
|
|
|
} else {
|
2010-04-13 08:59:55 +08:00
|
|
|
WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
|
2017-01-20 14:28:00 +08:00
|
|
|
}
|
2005-07-07 01:31:27 +08:00
|
|
|
}
|
|
|
|
|
2007-09-21 05:07:37 +08:00
|
|
|
static void
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
|
2007-09-21 05:07:37 +08:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint32_t cnt;
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2007-09-21 05:07:37 +08:00
|
|
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
|
|
2014-02-26 17:15:06 +08:00
|
|
|
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
2019-03-13 02:08:13 +08:00
|
|
|
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
2007-09-21 05:07:37 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
WRT_REG_DWORD(®->iobase_addr, 0x7C00);
|
|
|
|
RD_REG_DWORD(®->iobase_addr);
|
|
|
|
WRT_REG_DWORD(®->iobase_window, 0x0001);
|
|
|
|
for (cnt = 10000; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 &&
|
|
|
|
rval == QLA_SUCCESS; cnt--) {
|
|
|
|
if (cnt) {
|
|
|
|
WRT_REG_DWORD(®->iobase_window, 0x0001);
|
|
|
|
udelay(10);
|
|
|
|
} else
|
|
|
|
rval = QLA_FUNCTION_TIMEOUT;
|
|
|
|
}
|
|
|
|
if (rval == QLA_SUCCESS)
|
|
|
|
goto next_test;
|
|
|
|
|
2013-06-25 23:27:29 +08:00
|
|
|
rval = QLA_SUCCESS;
|
2007-09-21 05:07:37 +08:00
|
|
|
WRT_REG_DWORD(®->iobase_window, 0x0003);
|
|
|
|
for (cnt = 100; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 &&
|
|
|
|
rval == QLA_SUCCESS; cnt--) {
|
|
|
|
if (cnt) {
|
|
|
|
WRT_REG_DWORD(®->iobase_window, 0x0003);
|
|
|
|
udelay(10);
|
|
|
|
} else
|
|
|
|
rval = QLA_FUNCTION_TIMEOUT;
|
|
|
|
}
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
next_test:
|
|
|
|
if (RD_REG_DWORD(®->iobase_c8) & BIT_3)
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x504c,
|
|
|
|
"Additional code -- 0x55AA.\n");
|
2007-09-21 05:07:37 +08:00
|
|
|
|
|
|
|
done:
|
|
|
|
WRT_REG_DWORD(®->iobase_window, 0x0000);
|
|
|
|
RD_REG_DWORD(®->iobase_window);
|
|
|
|
}
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
/**
|
2012-02-10 03:15:34 +08:00
|
|
|
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
|
2018-10-19 06:45:41 +08:00
|
|
|
* @irq: interrupt number
|
2005-07-07 01:31:27 +08:00
|
|
|
* @dev_id: SCSI driver HA context
|
|
|
|
*
|
|
|
|
* Called by system whenever the host adapter generates an interrupt.
|
|
|
|
*
|
|
|
|
* Returns handled flag.
|
|
|
|
*/
|
|
|
|
irqreturn_t
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
qla24xx_intr_handler(int irq, void *dev_id)
|
2005-07-07 01:31:27 +08:00
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
scsi_qla_host_t *vha;
|
|
|
|
struct qla_hw_data *ha;
|
2005-07-07 01:31:27 +08:00
|
|
|
struct device_reg_24xx __iomem *reg;
|
|
|
|
int status;
|
|
|
|
unsigned long iter;
|
|
|
|
uint32_t stat;
|
|
|
|
uint32_t hccr;
|
2012-08-23 02:21:03 +08:00
|
|
|
uint16_t mb[8];
|
2008-11-07 02:40:51 +08:00
|
|
|
struct rsp_que *rsp;
|
2009-06-11 04:55:11 +08:00
|
|
|
unsigned long flags;
|
2018-09-05 05:19:10 +08:00
|
|
|
bool process_atio = false;
|
2005-07-07 01:31:27 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp = (struct rsp_que *) dev_id;
|
|
|
|
if (!rsp) {
|
2012-02-10 03:15:47 +08:00
|
|
|
ql_log(ql_log_info, NULL, 0x5059,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
2005-07-07 01:31:27 +08:00
|
|
|
return IRQ_NONE;
|
|
|
|
}
|
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha = rsp->hw;
|
2005-07-07 01:31:27 +08:00
|
|
|
reg = &ha->iobase->isp24;
|
|
|
|
status = 0;
|
|
|
|
|
2009-12-16 13:29:46 +08:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2009-04-07 13:33:40 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2005-07-07 01:31:27 +08:00
|
|
|
for (iter = 50; iter--; ) {
|
|
|
|
stat = RD_REG_DWORD(®->host_status);
|
2014-08-27 05:11:41 +08:00
|
|
|
if (qla2x00_check_reg32_for_disconnect(vha, stat))
|
2013-10-30 15:38:16 +08:00
|
|
|
break;
|
2005-07-07 01:31:27 +08:00
|
|
|
if (stat & HSRX_RISC_PAUSED) {
|
2009-12-16 13:29:46 +08:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
2007-09-21 05:07:36 +08:00
|
|
|
break;
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
hccr = RD_REG_DWORD(®->hccr);
|
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x504b,
|
|
|
|
"RISC paused -- HCCR=%x, Dumping firmware.\n",
|
|
|
|
hccr);
|
2007-09-21 05:07:37 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2xxx_check_risc_status(vha);
|
2007-09-21 05:07:37 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
|
|
|
} else if ((stat & HSRX_RISC_INT) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (stat & 0xff) {
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_ROM_MB_SUCCESS:
|
|
|
|
case INTR_ROM_MB_FAILED:
|
|
|
|
case INTR_MB_SUCCESS:
|
|
|
|
case INTR_MB_FAILED:
|
2008-11-07 02:40:51 +08:00
|
|
|
qla24xx_mbx_completion(vha, MSW(stat));
|
2005-07-07 01:31:27 +08:00
|
|
|
status |= MBX_INTERRUPT;
|
|
|
|
|
|
|
|
break;
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_ASYNC_EVENT:
|
2005-07-07 01:31:27 +08:00
|
|
|
mb[0] = MSW(stat);
|
|
|
|
mb[1] = RD_REG_WORD(®->mailbox1);
|
|
|
|
mb[2] = RD_REG_WORD(®->mailbox2);
|
|
|
|
mb[3] = RD_REG_WORD(®->mailbox3);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_RSP_QUE_UPDATE:
|
|
|
|
case INTR_RSP_QUE_UPDATE_83XX:
|
2009-04-07 13:33:40 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
2017-10-14 00:34:04 +08:00
|
|
|
case INTR_ATIO_QUE_UPDATE_27XX:
|
2018-09-05 05:19:10 +08:00
|
|
|
case INTR_ATIO_QUE_UPDATE:
|
|
|
|
process_atio = true;
|
2012-05-16 02:34:28 +08:00
|
|
|
break;
|
2018-09-05 05:19:10 +08:00
|
|
|
case INTR_ATIO_RSP_QUE_UPDATE:
|
|
|
|
process_atio = true;
|
2012-05-16 02:34:28 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
|
|
|
break;
|
2005-07-07 01:31:27 +08:00
|
|
|
default:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x504f,
|
|
|
|
"Unrecognized interrupt type (%d).\n", stat * 0xff);
|
2005-07-07 01:31:27 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
|
|
|
RD_REG_DWORD_RELAXED(®->hccr);
|
2012-08-23 02:21:30 +08:00
|
|
|
if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
|
|
|
|
ndelay(3500);
|
2005-07-07 01:31:27 +08:00
|
|
|
}
|
2013-04-24 01:13:17 +08:00
|
|
|
qla2x00_handle_mbx_completion(ha, status);
|
2009-06-11 04:55:11 +08:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2005-07-07 01:31:27 +08:00
|
|
|
|
2018-09-05 05:19:10 +08:00
|
|
|
if (process_atio) {
|
|
|
|
spin_lock_irqsave(&ha->tgt.atio_lock, flags);
|
|
|
|
qlt_24xx_process_atio_queue(vha, 0);
|
|
|
|
spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
|
|
|
|
}
|
|
|
|
|
2005-07-07 01:31:27 +08:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
static irqreturn_t
|
|
|
|
qla24xx_msix_rsp_q(int irq, void *dev_id)
|
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha;
|
|
|
|
struct rsp_que *rsp;
|
2007-01-30 02:22:19 +08:00
|
|
|
struct device_reg_24xx __iomem *reg;
|
2009-04-07 13:33:40 +08:00
|
|
|
struct scsi_qla_host *vha;
|
2010-01-29 18:09:30 +08:00
|
|
|
unsigned long flags;
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp = (struct rsp_que *) dev_id;
|
|
|
|
if (!rsp) {
|
2012-02-10 03:15:47 +08:00
|
|
|
ql_log(ql_log_info, NULL, 0x505a,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
2008-11-07 02:40:51 +08:00
|
|
|
return IRQ_NONE;
|
|
|
|
}
|
|
|
|
ha = rsp->hw;
|
2007-01-30 02:22:19 +08:00
|
|
|
reg = &ha->iobase->isp24;
|
|
|
|
|
2010-01-29 18:09:30 +08:00
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2010-02-05 06:17:59 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2009-04-07 13:33:40 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
2009-12-03 02:36:55 +08:00
|
|
|
if (!ha->flags.disable_msix_handshake) {
|
2009-08-05 07:12:13 +08:00
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
|
|
|
RD_REG_DWORD_RELAXED(®->hccr);
|
|
|
|
}
|
2010-01-29 18:09:30 +08:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2007-01-30 02:22:19 +08:00
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static irqreturn_t
|
|
|
|
qla24xx_msix_default(int irq, void *dev_id)
|
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
scsi_qla_host_t *vha;
|
|
|
|
struct qla_hw_data *ha;
|
|
|
|
struct rsp_que *rsp;
|
2007-01-30 02:22:19 +08:00
|
|
|
struct device_reg_24xx __iomem *reg;
|
|
|
|
int status;
|
|
|
|
uint32_t stat;
|
|
|
|
uint32_t hccr;
|
2012-08-23 02:21:03 +08:00
|
|
|
uint16_t mb[8];
|
2010-01-29 18:09:30 +08:00
|
|
|
unsigned long flags;
|
2018-09-05 05:19:10 +08:00
|
|
|
bool process_atio = false;
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
rsp = (struct rsp_que *) dev_id;
|
|
|
|
if (!rsp) {
|
2012-02-10 03:15:47 +08:00
|
|
|
ql_log(ql_log_info, NULL, 0x505c,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
2008-11-07 02:40:51 +08:00
|
|
|
return IRQ_NONE;
|
|
|
|
}
|
|
|
|
ha = rsp->hw;
|
2007-01-30 02:22:19 +08:00
|
|
|
reg = &ha->iobase->isp24;
|
|
|
|
status = 0;
|
|
|
|
|
2010-01-29 18:09:30 +08:00
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2009-04-07 13:33:40 +08:00
|
|
|
vha = pci_get_drvdata(ha->pdev);
|
2007-09-21 05:07:49 +08:00
|
|
|
do {
|
2007-01-30 02:22:19 +08:00
|
|
|
stat = RD_REG_DWORD(®->host_status);
|
2014-08-27 05:11:41 +08:00
|
|
|
if (qla2x00_check_reg32_for_disconnect(vha, stat))
|
2013-10-30 15:38:16 +08:00
|
|
|
break;
|
2007-01-30 02:22:19 +08:00
|
|
|
if (stat & HSRX_RISC_PAUSED) {
|
2009-12-16 13:29:46 +08:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
2007-09-21 05:07:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
hccr = RD_REG_DWORD(®->hccr);
|
|
|
|
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x5050,
|
|
|
|
"RISC paused -- HCCR=%x, Dumping firmware.\n",
|
|
|
|
hccr);
|
2007-09-21 05:07:37 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2xxx_check_risc_status(vha);
|
2007-09-21 05:07:37 +08:00
|
|
|
|
2008-11-07 02:40:51 +08:00
|
|
|
ha->isp_ops->fw_dump(vha, 1);
|
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2007-01-30 02:22:19 +08:00
|
|
|
break;
|
|
|
|
} else if ((stat & HSRX_RISC_INT) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (stat & 0xff) {
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_ROM_MB_SUCCESS:
|
|
|
|
case INTR_ROM_MB_FAILED:
|
|
|
|
case INTR_MB_SUCCESS:
|
|
|
|
case INTR_MB_FAILED:
|
2008-11-07 02:40:51 +08:00
|
|
|
qla24xx_mbx_completion(vha, MSW(stat));
|
2007-01-30 02:22:19 +08:00
|
|
|
status |= MBX_INTERRUPT;
|
|
|
|
|
|
|
|
break;
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_ASYNC_EVENT:
|
2007-01-30 02:22:19 +08:00
|
|
|
mb[0] = MSW(stat);
|
|
|
|
mb[1] = RD_REG_WORD(®->mailbox1);
|
|
|
|
mb[2] = RD_REG_WORD(®->mailbox2);
|
|
|
|
mb[3] = RD_REG_WORD(®->mailbox3);
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_async_event(vha, rsp, mb);
|
2007-01-30 02:22:19 +08:00
|
|
|
break;
|
2012-08-23 02:21:16 +08:00
|
|
|
case INTR_RSP_QUE_UPDATE:
|
|
|
|
case INTR_RSP_QUE_UPDATE_83XX:
|
2009-04-07 13:33:40 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
2007-01-30 02:22:19 +08:00
|
|
|
break;
|
2017-10-14 00:34:04 +08:00
|
|
|
case INTR_ATIO_QUE_UPDATE_27XX:
|
2018-09-05 05:19:10 +08:00
|
|
|
case INTR_ATIO_QUE_UPDATE:
|
|
|
|
process_atio = true;
|
2012-05-16 02:34:28 +08:00
|
|
|
break;
|
2018-09-05 05:19:10 +08:00
|
|
|
case INTR_ATIO_RSP_QUE_UPDATE:
|
|
|
|
process_atio = true;
|
2012-05-16 02:34:28 +08:00
|
|
|
qla24xx_process_response_queue(vha, rsp);
|
|
|
|
break;
|
2007-01-30 02:22:19 +08:00
|
|
|
default:
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_async, vha, 0x5051,
|
|
|
|
"Unrecognized interrupt type (%d).\n", stat & 0xff);
|
2007-01-30 02:22:19 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
2007-09-21 05:07:49 +08:00
|
|
|
} while (0);
|
2013-04-24 01:13:17 +08:00
|
|
|
qla2x00_handle_mbx_completion(ha, status);
|
2010-01-29 18:09:30 +08:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2018-09-05 05:19:10 +08:00
|
|
|
if (process_atio) {
|
|
|
|
spin_lock_irqsave(&ha->tgt.atio_lock, flags);
|
|
|
|
qlt_24xx_process_atio_queue(vha, 0);
|
|
|
|
spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
|
|
|
|
}
|
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2016-12-13 06:40:07 +08:00
|
|
|
irqreturn_t
|
|
|
|
qla2xxx_msix_rsp_q(int irq, void *dev_id)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha;
|
|
|
|
struct qla_qpair *qpair;
|
|
|
|
struct device_reg_24xx __iomem *reg;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
qpair = dev_id;
|
|
|
|
if (!qpair) {
|
|
|
|
ql_log(ql_log_info, NULL, 0x505b,
|
|
|
|
"%s: NULL response queue pointer.\n", __func__);
|
|
|
|
return IRQ_NONE;
|
|
|
|
}
|
|
|
|
ha = qpair->hw;
|
|
|
|
|
|
|
|
/* Clear the interrupt, if enabled, for this response queue */
|
|
|
|
if (unlikely(!ha->flags.disable_msix_handshake)) {
|
|
|
|
reg = &ha->iobase->isp24;
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
queue_work(ha->wq, &qpair->q_work);
|
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
/* Interrupt handling helpers. */
|
|
|
|
|
|
|
|
struct qla_init_msix_entry {
|
|
|
|
const char *name;
|
2007-05-24 05:41:44 +08:00
|
|
|
irq_handler_t handler;
|
2007-01-30 02:22:19 +08:00
|
|
|
};
|
|
|
|
|
2016-12-26 21:23:10 +08:00
|
|
|
static const struct qla_init_msix_entry msix_entries[] = {
|
2017-06-14 11:47:18 +08:00
|
|
|
{ "default", qla24xx_msix_default },
|
|
|
|
{ "rsp_q", qla24xx_msix_rsp_q },
|
|
|
|
{ "atio_q", qla83xx_msix_atio_q },
|
|
|
|
{ "qpair_multiq", qla2xxx_msix_rsp_q },
|
2007-01-30 02:22:19 +08:00
|
|
|
};
|
|
|
|
|
2016-12-26 21:23:10 +08:00
|
|
|
static const struct qla_init_msix_entry qla82xx_msix_entries[] = {
|
2010-04-13 08:59:55 +08:00
|
|
|
{ "qla2xxx (default)", qla82xx_msix_default },
|
|
|
|
{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
|
|
|
|
};
|
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
static int
|
2008-12-10 08:45:39 +08:00
|
|
|
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
|
2007-01-30 02:22:19 +08:00
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
struct qla_msix_entry *qentry;
|
2011-07-15 03:00:13 +08:00
|
|
|
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
2017-02-16 07:37:21 +08:00
|
|
|
int min_vecs = QLA_BASE_VECTORS;
|
2017-01-12 00:55:45 +08:00
|
|
|
struct irq_affinity desc = {
|
|
|
|
.pre_vectors = QLA_BASE_VECTORS,
|
|
|
|
};
|
|
|
|
|
2017-10-14 00:34:04 +08:00
|
|
|
if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
|
|
|
|
IS_ATIO_MSIX_CAPABLE(ha)) {
|
2017-01-12 00:55:45 +08:00
|
|
|
desc.pre_vectors++;
|
2017-02-16 07:37:21 +08:00
|
|
|
min_vecs++;
|
|
|
|
}
|
2017-01-12 00:55:45 +08:00
|
|
|
|
2019-02-16 08:42:55 +08:00
|
|
|
if (USER_CTRL_IRQ(ha) || !ha->mqiobase) {
|
2017-06-14 11:47:20 +08:00
|
|
|
/* user wants to control IRQ setting for target mode */
|
|
|
|
ret = pci_alloc_irq_vectors(ha->pdev, min_vecs,
|
|
|
|
ha->msix_count, PCI_IRQ_MSIX);
|
|
|
|
} else
|
|
|
|
ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs,
|
|
|
|
ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
|
|
|
|
&desc);
|
2008-12-10 08:45:39 +08:00
|
|
|
|
2014-08-18 14:01:47 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
ql_log(ql_log_fatal, vha, 0x00c7,
|
|
|
|
"MSI-X: Failed to enable support, "
|
|
|
|
"giving up -- %d/%d.\n",
|
|
|
|
ha->msix_count, ret);
|
|
|
|
goto msix_out;
|
|
|
|
} else if (ret < ha->msix_count) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x00c6,
|
|
|
|
"MSI-X: Failed to enable support "
|
2016-12-13 06:40:07 +08:00
|
|
|
"with %d vectors, using %d vectors.\n",
|
|
|
|
ha->msix_count, ret);
|
2016-02-05 00:45:16 +08:00
|
|
|
ha->msix_count = ret;
|
2016-12-13 06:40:07 +08:00
|
|
|
/* Recalculate queue values */
|
2017-10-14 06:43:22 +08:00
|
|
|
if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) {
|
2016-12-13 06:40:07 +08:00
|
|
|
ha->max_req_queues = ha->msix_count - 1;
|
|
|
|
|
|
|
|
/* ATIOQ needs 1 vector. That's 1 less QPair */
|
|
|
|
if (QLA_TGT_MODE_ENABLED())
|
|
|
|
ha->max_req_queues--;
|
|
|
|
|
|
|
|
ha->max_rsp_queues = ha->max_req_queues;
|
|
|
|
|
|
|
|
ha->max_qpairs = ha->max_req_queues - 1;
|
|
|
|
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190,
|
|
|
|
"Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs);
|
|
|
|
}
|
2008-12-10 08:45:39 +08:00
|
|
|
}
|
2019-01-12 01:40:47 +08:00
|
|
|
vha->irq_offset = desc.pre_vectors;
|
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-13 05:03:40 +08:00
|
|
|
ha->msix_entries = kcalloc(ha->msix_count,
|
|
|
|
sizeof(struct qla_msix_entry),
|
|
|
|
GFP_KERNEL);
|
2008-12-10 08:45:39 +08:00
|
|
|
if (!ha->msix_entries) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_fatal, vha, 0x00c8,
|
|
|
|
"Failed to allocate memory for ha->msix_entries.\n");
|
2008-12-10 08:45:39 +08:00
|
|
|
ret = -ENOMEM;
|
2019-04-18 05:44:24 +08:00
|
|
|
goto free_irqs;
|
2007-01-30 02:22:19 +08:00
|
|
|
}
|
|
|
|
ha->flags.msix_enabled = 1;
|
|
|
|
|
2008-12-10 08:45:39 +08:00
|
|
|
for (i = 0; i < ha->msix_count; i++) {
|
|
|
|
qentry = &ha->msix_entries[i];
|
2016-12-13 06:40:06 +08:00
|
|
|
qentry->vector = pci_irq_vector(ha->pdev, i);
|
|
|
|
qentry->entry = i;
|
2007-01-30 02:22:19 +08:00
|
|
|
qentry->have_irq = 0;
|
2016-12-13 06:40:07 +08:00
|
|
|
qentry->in_use = 0;
|
2016-12-13 06:40:06 +08:00
|
|
|
qentry->handle = NULL;
|
2007-01-30 02:22:19 +08:00
|
|
|
}
|
|
|
|
|
2009-04-07 13:33:40 +08:00
|
|
|
/* Enable MSI-X vectors for the base queue */
|
2017-01-12 00:55:45 +08:00
|
|
|
for (i = 0; i < QLA_BASE_VECTORS; i++) {
|
2009-04-07 13:33:40 +08:00
|
|
|
qentry = &ha->msix_entries[i];
|
2016-12-13 06:40:06 +08:00
|
|
|
qentry->handle = rsp;
|
2016-07-06 15:51:50 +08:00
|
|
|
rsp->msix = qentry;
|
2016-12-13 06:40:07 +08:00
|
|
|
scnprintf(qentry->name, sizeof(qentry->name),
|
2017-06-14 11:47:18 +08:00
|
|
|
"qla2xxx%lu_%s", vha->host_no, msix_entries[i].name);
|
2014-02-26 17:15:14 +08:00
|
|
|
if (IS_P3P_TYPE(ha))
|
2010-04-13 08:59:55 +08:00
|
|
|
ret = request_irq(qentry->vector,
|
|
|
|
qla82xx_msix_entries[i].handler,
|
|
|
|
0, qla82xx_msix_entries[i].name, rsp);
|
2014-02-26 17:15:14 +08:00
|
|
|
else
|
2010-04-13 08:59:55 +08:00
|
|
|
ret = request_irq(qentry->vector,
|
|
|
|
msix_entries[i].handler,
|
2017-06-14 11:47:18 +08:00
|
|
|
0, qentry->name, rsp);
|
2014-02-26 17:15:14 +08:00
|
|
|
if (ret)
|
|
|
|
goto msix_register_fail;
|
|
|
|
qentry->have_irq = 1;
|
2016-12-13 06:40:09 +08:00
|
|
|
qentry->in_use = 1;
|
2014-02-26 17:15:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If target mode is enable, also request the vector for the ATIO
|
|
|
|
* queue.
|
|
|
|
*/
|
2017-10-14 00:34:04 +08:00
|
|
|
if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
|
|
|
|
IS_ATIO_MSIX_CAPABLE(ha)) {
|
2016-12-13 06:40:09 +08:00
|
|
|
qentry = &ha->msix_entries[QLA_ATIO_VECTOR];
|
2016-07-06 15:51:50 +08:00
|
|
|
rsp->msix = qentry;
|
2016-12-13 06:40:07 +08:00
|
|
|
qentry->handle = rsp;
|
|
|
|
scnprintf(qentry->name, sizeof(qentry->name),
|
2017-06-14 11:47:18 +08:00
|
|
|
"qla2xxx%lu_%s", vha->host_no,
|
|
|
|
msix_entries[QLA_ATIO_VECTOR].name);
|
2016-12-13 06:40:09 +08:00
|
|
|
qentry->in_use = 1;
|
2014-02-26 17:15:14 +08:00
|
|
|
ret = request_irq(qentry->vector,
|
2016-12-13 06:40:09 +08:00
|
|
|
msix_entries[QLA_ATIO_VECTOR].handler,
|
2017-06-14 11:47:18 +08:00
|
|
|
0, qentry->name, rsp);
|
2009-04-07 13:33:40 +08:00
|
|
|
qentry->have_irq = 1;
|
2008-12-10 08:45:39 +08:00
|
|
|
}
|
|
|
|
|
2014-02-26 17:15:14 +08:00
|
|
|
msix_register_fail:
|
|
|
|
if (ret) {
|
|
|
|
ql_log(ql_log_fatal, vha, 0x00cb,
|
|
|
|
"MSI-X: unable to register handler -- %x/%d.\n",
|
|
|
|
qentry->vector, ret);
|
2016-12-13 06:40:06 +08:00
|
|
|
qla2x00_free_irqs(vha);
|
2014-02-26 17:15:14 +08:00
|
|
|
ha->mqenable = 0;
|
|
|
|
goto msix_out;
|
|
|
|
}
|
|
|
|
|
2008-12-10 08:45:39 +08:00
|
|
|
/* Enable MSI-X vector for response queue update for queue 0 */
|
2019-03-13 02:08:13 +08:00
|
|
|
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
2012-02-10 03:15:34 +08:00
|
|
|
if (ha->msixbase && ha->mqiobase &&
|
2016-12-13 06:40:07 +08:00
|
|
|
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1 ||
|
|
|
|
ql2xmqsupport))
|
2012-02-10 03:15:34 +08:00
|
|
|
ha->mqenable = 1;
|
|
|
|
} else
|
2016-12-13 06:40:07 +08:00
|
|
|
if (ha->mqiobase &&
|
|
|
|
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1 ||
|
|
|
|
ql2xmqsupport))
|
2012-02-10 03:15:34 +08:00
|
|
|
ha->mqenable = 1;
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_multiq, vha, 0xc005,
|
|
|
|
"mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
|
|
|
|
ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
|
|
|
|
ql_dbg(ql_dbg_init, vha, 0x0055,
|
|
|
|
"mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
|
|
|
|
ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
|
2008-12-10 08:45:39 +08:00
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
msix_out:
|
|
|
|
return ret;
|
2019-04-18 05:44:24 +08:00
|
|
|
|
|
|
|
free_irqs:
|
|
|
|
pci_free_irq_vectors(ha->pdev);
|
|
|
|
goto msix_out;
|
2007-01-30 02:22:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-12-10 08:45:39 +08:00
|
|
|
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
|
2007-01-30 02:22:19 +08:00
|
|
|
{
|
2013-10-30 15:38:10 +08:00
|
|
|
int ret = QLA_FUNCTION_FAILED;
|
2014-02-26 17:15:06 +08:00
|
|
|
device_reg_t *reg = ha->iobase;
|
2011-07-15 03:00:13 +08:00
|
|
|
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
2007-01-30 02:22:19 +08:00
|
|
|
|
|
|
|
/* If possible, enable MSI-X. */
|
2017-10-14 00:34:03 +08:00
|
|
|
if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
|
|
|
|
!IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
|
2019-03-13 02:08:13 +08:00
|
|
|
!IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
|
2010-03-20 07:59:19 +08:00
|
|
|
goto skip_msi;
|
|
|
|
|
2017-10-14 00:34:03 +08:00
|
|
|
if (ql2xenablemsix == 2)
|
|
|
|
goto skip_msix;
|
|
|
|
|
2010-03-20 07:59:19 +08:00
|
|
|
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
|
|
|
|
(ha->pdev->subsystem_device == 0x7040 ||
|
|
|
|
ha->pdev->subsystem_device == 0x7041 ||
|
|
|
|
ha->pdev->subsystem_device == 0x1705)) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x0034,
|
|
|
|
"MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
|
2010-03-20 07:59:19 +08:00
|
|
|
ha->pdev->subsystem_vendor,
|
2011-07-15 03:00:13 +08:00
|
|
|
ha->pdev->subsystem_device);
|
2010-03-20 07:59:19 +08:00
|
|
|
goto skip_msi;
|
|
|
|
}
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2011-08-17 02:29:24 +08:00
|
|
|
if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x0035,
|
|
|
|
"MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
|
2011-08-17 02:29:24 +08:00
|
|
|
ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
|
2007-01-30 02:22:19 +08:00
|
|
|
goto skip_msix;
|
|
|
|
}
|
|
|
|
|
2008-12-10 08:45:39 +08:00
|
|
|
ret = qla24xx_enable_msix(ha, rsp);
|
2007-01-30 02:22:19 +08:00
|
|
|
if (!ret) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_init, vha, 0x0036,
|
|
|
|
"MSI-X: Enabled (0x%X, 0x%X).\n",
|
|
|
|
ha->chip_revision, ha->fw_attributes);
|
2008-02-01 04:33:50 +08:00
|
|
|
goto clear_risc_ints;
|
2007-01-30 02:22:19 +08:00
|
|
|
}
|
2013-10-30 15:38:10 +08:00
|
|
|
|
2007-01-30 02:22:19 +08:00
|
|
|
skip_msix:
|
2007-05-07 22:43:02 +08:00
|
|
|
|
2013-10-30 15:38:10 +08:00
|
|
|
ql_log(ql_log_info, vha, 0x0037,
|
|
|
|
"Falling back-to MSI mode -%d.\n", ret);
|
|
|
|
|
2009-01-06 03:18:11 +08:00
|
|
|
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
|
2014-02-26 17:15:06 +08:00
|
|
|
!IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
|
2019-03-13 02:08:13 +08:00
|
|
|
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
2007-05-07 22:43:02 +08:00
|
|
|
goto skip_msi;
|
|
|
|
|
2016-12-13 06:40:06 +08:00
|
|
|
ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
|
2007-05-07 22:43:02 +08:00
|
|
|
if (!ret) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_dbg(ql_dbg_init, vha, 0x0038,
|
|
|
|
"MSI: Enabled.\n");
|
2007-05-07 22:43:02 +08:00
|
|
|
ha->flags.msi_enabled = 1;
|
2010-04-13 08:59:55 +08:00
|
|
|
} else
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x0039,
|
2013-10-30 15:38:10 +08:00
|
|
|
"Falling back-to INTa mode -- %d.\n", ret);
|
|
|
|
skip_msi:
|
2012-08-23 02:21:07 +08:00
|
|
|
|
|
|
|
/* Skip INTx on ISP82xx. */
|
|
|
|
if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
|
2007-07-20 06:06:00 +08:00
|
|
|
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
|
2010-11-24 08:52:47 +08:00
|
|
|
ha->flags.msi_enabled ? 0 : IRQF_SHARED,
|
|
|
|
QLA2XXX_DRIVER_NAME, rsp);
|
2008-02-01 04:33:50 +08:00
|
|
|
if (ret) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_warn, vha, 0x003a,
|
2007-01-30 02:22:19 +08:00
|
|
|
"Failed to reserve interrupt %d already in use.\n",
|
|
|
|
ha->pdev->irq);
|
2008-02-01 04:33:50 +08:00
|
|
|
goto fail;
|
2013-03-28 20:21:23 +08:00
|
|
|
} else if (!ha->flags.msi_enabled) {
|
2012-11-21 15:40:44 +08:00
|
|
|
ql_dbg(ql_dbg_init, vha, 0x0125,
|
|
|
|
"INTa mode: Enabled.\n");
|
2013-03-28 20:21:23 +08:00
|
|
|
ha->flags.mr_intr_valid = 1;
|
|
|
|
}
|
2010-11-24 08:52:47 +08:00
|
|
|
|
2008-02-01 04:33:50 +08:00
|
|
|
clear_risc_ints:
|
2014-09-25 17:16:42 +08:00
|
|
|
if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
|
|
|
|
goto fail;
|
2008-02-01 04:33:50 +08:00
|
|
|
|
2008-04-04 04:13:17 +08:00
|
|
|
spin_lock_irq(&ha->hardware_lock);
|
2014-09-25 17:16:42 +08:00
|
|
|
WRT_REG_WORD(®->isp.semaphore, 0);
|
2008-04-04 04:13:17 +08:00
|
|
|
spin_unlock_irq(&ha->hardware_lock);
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2008-02-01 04:33:50 +08:00
|
|
|
fail:
|
2007-01-30 02:22:19 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-11-07 02:40:51 +08:00
|
|
|
qla2x00_free_irqs(scsi_qla_host_t *vha)
|
2007-01-30 02:22:19 +08:00
|
|
|
{
|
2008-11-07 02:40:51 +08:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2012-05-16 02:34:14 +08:00
|
|
|
struct rsp_que *rsp;
|
2016-12-13 06:40:06 +08:00
|
|
|
struct qla_msix_entry *qentry;
|
|
|
|
int i;
|
2012-05-16 02:34:14 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to check that ha->rsp_q_map is valid in case we are called
|
|
|
|
* from a probe failure context.
|
|
|
|
*/
|
|
|
|
if (!ha->rsp_q_map || !ha->rsp_q_map[0])
|
2017-01-24 00:34:45 +08:00
|
|
|
goto free_irqs;
|
2012-05-16 02:34:14 +08:00
|
|
|
rsp = ha->rsp_q_map[0];
|
2007-01-30 02:22:19 +08:00
|
|
|
|
2016-12-13 06:40:06 +08:00
|
|
|
if (ha->flags.msix_enabled) {
|
|
|
|
for (i = 0; i < ha->msix_count; i++) {
|
|
|
|
qentry = &ha->msix_entries[i];
|
|
|
|
if (qentry->have_irq) {
|
|
|
|
irq_set_affinity_notifier(qentry->vector, NULL);
|
|
|
|
free_irq(pci_irq_vector(ha->pdev, i), qentry->handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kfree(ha->msix_entries);
|
|
|
|
ha->msix_entries = NULL;
|
|
|
|
ha->flags.msix_enabled = 0;
|
|
|
|
ql_dbg(ql_dbg_init, vha, 0x0042,
|
|
|
|
"Disabled MSI-X.\n");
|
|
|
|
} else {
|
|
|
|
free_irq(pci_irq_vector(ha->pdev, 0), rsp);
|
|
|
|
}
|
2008-11-07 02:40:51 +08:00
|
|
|
|
2017-01-24 00:34:45 +08:00
|
|
|
free_irqs:
|
2016-12-13 06:40:06 +08:00
|
|
|
pci_free_irq_vectors(ha->pdev);
|
2007-01-30 02:22:19 +08:00
|
|
|
}
|
2008-12-10 08:45:39 +08:00
|
|
|
|
2016-12-13 06:40:07 +08:00
|
|
|
int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
|
|
|
|
struct qla_msix_entry *msix, int vector_type)
|
2008-12-10 08:45:39 +08:00
|
|
|
{
|
2016-12-26 21:23:10 +08:00
|
|
|
const struct qla_init_msix_entry *intr = &msix_entries[vector_type];
|
2011-07-15 03:00:13 +08:00
|
|
|
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
2008-12-10 08:45:39 +08:00
|
|
|
int ret;
|
|
|
|
|
2016-12-13 06:40:07 +08:00
|
|
|
scnprintf(msix->name, sizeof(msix->name),
|
|
|
|
"qla2xxx%lu_qpair%d", vha->host_no, qpair->id);
|
|
|
|
ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair);
|
2008-12-10 08:45:39 +08:00
|
|
|
if (ret) {
|
2011-07-15 03:00:13 +08:00
|
|
|
ql_log(ql_log_fatal, vha, 0x00e6,
|
|
|
|
"MSI-X: Unable to register handler -- %x/%d.\n",
|
|
|
|
msix->vector, ret);
|
2008-12-10 08:45:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
msix->have_irq = 1;
|
2016-12-13 06:40:07 +08:00
|
|
|
msix->handle = qpair;
|
2008-12-10 08:45:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|