scsi: qla2xxx: Fix crash in PCIe error handling
[ Upstream commit f7a0ed479e66ab177801301a1a72c37775c40450 ] BUG: unable to handle kernel NULL pointer dereference at (null) IP: qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 0 PID: 1715 Comm: kworker/0:2 Tainted: GOE 4.12.14-122.37-default #1 SLE12-SP5 Hardware name: HPE Superdome Flex/Superdome Flex, BIOS Bundle:3.30.100 SFW:IP147.007.004.017.000.2009211957 09/21/2020 Workqueue: events aer_recover_work_func task: ffff9e399c14ca80 task.stack: ffffc1c58e4ac000 RIP: 0010:qla2x00_abort_isp+0x21/0x6b0 [qla2xxx] RSP: 0018:ffffc1c58e4afd50 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9e419cdef480 RCX: 0000000000000000 RDX: ffff9e399c14ca80 RSI: 0000000000000246 RDI: ffff9e419bbc27b8 RBP: ffff9e419bbc27b8 R08: 0000000000000004 R09: 00000000a0440000 R10: 0000000000000000 R11: ffff9e399416d1a0 R12: ffff9e419cdef000 R13: ffff9e3a7cfae800 R14: ffff9e3a7cfae800 R15: 00000000000000c0 FS: 0000000000000000(0000) GS:ffff9e39a0000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000006cd00a005 CR4: 00000000007606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: qla2xxx_pci_slot_reset+0x141/0x160 [qla2xxx] report_slot_reset+0x41/0x80 ? merge_result.part.4+0x30/0x30 pci_walk_bus+0x70/0x90 pcie_do_recovery+0x1db/0x2e0 aer_recover_work_func+0xc2/0xf0 process_one_work+0x14c/0x390 Disable board_disable logic where driver resources are freed while OS is in the process of recovering the adapter. Link: https://lore.kernel.org/r/20210329085229.4367-9-njavali@marvell.com Tested-by: Laurence Oberman <loberman@redhat.com> Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Stable-dep-of: 6d0b65569c0a ("scsi: qla2xxx: Flush mailbox commands on chip reset") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
41a660c204
commit
b5775b8530
@@ -112,8 +112,13 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
|
|||||||
uint32_t stat;
|
uint32_t stat;
|
||||||
ulong i, j, timer = 6000000;
|
ulong i, j, timer = 6000000;
|
||||||
int rval = QLA_FUNCTION_FAILED;
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
||||||
|
|
||||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||||
|
|
||||||
|
if (qla_pci_disconnected(vha, reg))
|
||||||
|
return rval;
|
||||||
|
|
||||||
for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
|
for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
|
||||||
if (i + dwords > ram_dwords)
|
if (i + dwords > ram_dwords)
|
||||||
dwords = ram_dwords - i;
|
dwords = ram_dwords - i;
|
||||||
@@ -137,6 +142,9 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
|
|||||||
while (timer--) {
|
while (timer--) {
|
||||||
udelay(5);
|
udelay(5);
|
||||||
|
|
||||||
|
if (qla_pci_disconnected(vha, reg))
|
||||||
|
return rval;
|
||||||
|
|
||||||
stat = rd_reg_dword(®->host_status);
|
stat = rd_reg_dword(®->host_status);
|
||||||
/* Check for pending interrupts. */
|
/* Check for pending interrupts. */
|
||||||
if (!(stat & HSRX_RISC_INT))
|
if (!(stat & HSRX_RISC_INT))
|
||||||
@@ -191,9 +199,13 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram,
|
|||||||
uint32_t dwords = qla2x00_gid_list_size(ha) / 4;
|
uint32_t dwords = qla2x00_gid_list_size(ha) / 4;
|
||||||
uint32_t stat;
|
uint32_t stat;
|
||||||
ulong i, j, timer = 6000000;
|
ulong i, j, timer = 6000000;
|
||||||
|
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
||||||
|
|
||||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||||
|
|
||||||
|
if (qla_pci_disconnected(vha, reg))
|
||||||
|
return rval;
|
||||||
|
|
||||||
for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
|
for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
|
||||||
if (i + dwords > ram_dwords)
|
if (i + dwords > ram_dwords)
|
||||||
dwords = ram_dwords - i;
|
dwords = ram_dwords - i;
|
||||||
@@ -215,8 +227,10 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram,
|
|||||||
ha->flags.mbox_int = 0;
|
ha->flags.mbox_int = 0;
|
||||||
while (timer--) {
|
while (timer--) {
|
||||||
udelay(5);
|
udelay(5);
|
||||||
stat = rd_reg_dword(®->host_status);
|
if (qla_pci_disconnected(vha, reg))
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
stat = rd_reg_dword(®->host_status);
|
||||||
/* Check for pending interrupts. */
|
/* Check for pending interrupts. */
|
||||||
if (!(stat & HSRX_RISC_INT))
|
if (!(stat & HSRX_RISC_INT))
|
||||||
continue;
|
continue;
|
||||||
|
@@ -396,6 +396,7 @@ typedef union {
|
|||||||
} b;
|
} b;
|
||||||
} port_id_t;
|
} port_id_t;
|
||||||
#define INVALID_PORT_ID 0xFFFFFF
|
#define INVALID_PORT_ID 0xFFFFFF
|
||||||
|
#define ISP_REG16_DISCONNECT 0xFFFF
|
||||||
|
|
||||||
static inline le_id_t be_id_to_le(be_id_t id)
|
static inline le_id_t be_id_to_le(be_id_t id)
|
||||||
{
|
{
|
||||||
@@ -3848,6 +3849,13 @@ struct qla_hw_data_stat {
|
|||||||
u32 num_mpi_reset;
|
u32 num_mpi_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* refer to pcie_do_recovery reference */
|
||||||
|
typedef enum {
|
||||||
|
QLA_PCI_RESUME,
|
||||||
|
QLA_PCI_ERR_DETECTED,
|
||||||
|
QLA_PCI_MMIO_ENABLED,
|
||||||
|
QLA_PCI_SLOT_RESET,
|
||||||
|
} pci_error_state_t;
|
||||||
/*
|
/*
|
||||||
* Qlogic host adapter specific data structure.
|
* Qlogic host adapter specific data structure.
|
||||||
*/
|
*/
|
||||||
@@ -4586,6 +4594,7 @@ struct qla_hw_data {
|
|||||||
#define DEFAULT_ZIO_THRESHOLD 5
|
#define DEFAULT_ZIO_THRESHOLD 5
|
||||||
|
|
||||||
struct qla_hw_data_stat stat;
|
struct qla_hw_data_stat stat;
|
||||||
|
pci_error_state_t pci_error_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct active_regions {
|
struct active_regions {
|
||||||
@@ -4706,6 +4715,7 @@ typedef struct scsi_qla_host {
|
|||||||
#define FX00_CRITEMP_RECOVERY 25
|
#define FX00_CRITEMP_RECOVERY 25
|
||||||
#define FX00_HOST_INFO_RESEND 26
|
#define FX00_HOST_INFO_RESEND 26
|
||||||
#define QPAIR_ONLINE_CHECK_NEEDED 27
|
#define QPAIR_ONLINE_CHECK_NEEDED 27
|
||||||
|
#define DO_EEH_RECOVERY 28
|
||||||
#define DETECT_SFP_CHANGE 29
|
#define DETECT_SFP_CHANGE 29
|
||||||
#define N2N_LOGIN_NEEDED 30
|
#define N2N_LOGIN_NEEDED 30
|
||||||
#define IOCB_WORK_ACTIVE 31
|
#define IOCB_WORK_ACTIVE 31
|
||||||
|
@@ -222,6 +222,7 @@ extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
|
|||||||
|
|
||||||
extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
|
extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
|
||||||
extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
|
extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
|
||||||
|
extern void qla_eeh_work(struct work_struct *);
|
||||||
extern void qla2x00_sp_compl(srb_t *sp, int);
|
extern void qla2x00_sp_compl(srb_t *sp, int);
|
||||||
extern void qla2xxx_qpair_sp_free_dma(srb_t *sp);
|
extern void qla2xxx_qpair_sp_free_dma(srb_t *sp);
|
||||||
extern void qla2xxx_qpair_sp_compl(srb_t *sp, int);
|
extern void qla2xxx_qpair_sp_compl(srb_t *sp, int);
|
||||||
@@ -233,6 +234,8 @@ int qla24xx_post_relogin_work(struct scsi_qla_host *vha);
|
|||||||
void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
|
void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
|
||||||
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||||
struct purex_item *pkt);
|
struct purex_item *pkt);
|
||||||
|
void qla_pci_set_eeh_busy(struct scsi_qla_host *);
|
||||||
|
void qla_schedule_eeh_work(struct scsi_qla_host *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global Functions in qla_mid.c source file.
|
* Global Functions in qla_mid.c source file.
|
||||||
|
@@ -6982,22 +6982,18 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
|||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||||
|
|
||||||
if (!ha->flags.eeh_busy) {
|
/* Make sure for ISP 82XX IO DMA is complete */
|
||||||
/* Make sure for ISP 82XX IO DMA is complete */
|
if (IS_P3P_TYPE(ha)) {
|
||||||
if (IS_P3P_TYPE(ha)) {
|
qla82xx_chip_reset_cleanup(vha);
|
||||||
qla82xx_chip_reset_cleanup(vha);
|
ql_log(ql_log_info, vha, 0x00b4,
|
||||||
ql_log(ql_log_info, vha, 0x00b4,
|
"Done chip reset cleanup.\n");
|
||||||
"Done chip reset cleanup.\n");
|
|
||||||
|
|
||||||
/* Done waiting for pending commands.
|
/* Done waiting for pending commands. Reset online flag */
|
||||||
* Reset the online flag.
|
vha->flags.online = 0;
|
||||||
*/
|
|
||||||
vha->flags.online = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Requeue all commands in outstanding command list. */
|
|
||||||
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Requeue all commands in outstanding command list. */
|
||||||
|
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
|
||||||
/* memory barrier */
|
/* memory barrier */
|
||||||
wmb();
|
wmb();
|
||||||
}
|
}
|
||||||
@@ -7025,6 +7021,12 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
|
|||||||
if (vha->flags.online) {
|
if (vha->flags.online) {
|
||||||
qla2x00_abort_isp_cleanup(vha);
|
qla2x00_abort_isp_cleanup(vha);
|
||||||
|
|
||||||
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
|
ql_log(ql_log_info, vha, 0x803f,
|
||||||
|
"ISP Abort - ISP reg disconnect, exiting.\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
|
if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
|
||||||
ha->flags.chip_reset_done = 1;
|
ha->flags.chip_reset_done = 1;
|
||||||
vha->flags.online = 1;
|
vha->flags.online = 1;
|
||||||
@@ -7065,8 +7067,18 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
|
|||||||
|
|
||||||
ha->isp_ops->get_flash_version(vha, req->ring);
|
ha->isp_ops->get_flash_version(vha, req->ring);
|
||||||
|
|
||||||
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
|
ql_log(ql_log_info, vha, 0x803f,
|
||||||
|
"ISP Abort - ISP reg disconnect pre nvram config, exiting.\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
ha->isp_ops->nvram_config(vha);
|
ha->isp_ops->nvram_config(vha);
|
||||||
|
|
||||||
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
|
ql_log(ql_log_info, vha, 0x803f,
|
||||||
|
"ISP Abort - ISP reg disconnect post nvmram config, exiting.\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
if (!qla2x00_restart_isp(vha)) {
|
if (!qla2x00_restart_isp(vha)) {
|
||||||
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
||||||
|
|
||||||
|
@@ -435,3 +435,49 @@ qla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
|
|||||||
}
|
}
|
||||||
iores->res_type = RESOURCE_NONE;
|
iores->res_type = RESOURCE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ISP_REG_DISCONNECT 0xffffffffU
|
||||||
|
/**************************************************************************
|
||||||
|
* qla2x00_isp_reg_stat
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Read the host status register of ISP before aborting the command.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* ha = pointer to host adapter structure.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Either true or false.
|
||||||
|
*
|
||||||
|
* Note: Return true if there is register disconnect.
|
||||||
|
**************************************************************************/
|
||||||
|
static inline
|
||||||
|
uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha)
|
||||||
|
{
|
||||||
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||||
|
struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
|
||||||
|
|
||||||
|
if (IS_P3P_TYPE(ha))
|
||||||
|
return ((rd_reg_dword(®82->host_int)) == ISP_REG_DISCONNECT);
|
||||||
|
else
|
||||||
|
return ((rd_reg_dword(®->host_status)) ==
|
||||||
|
ISP_REG_DISCONNECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool qla_pci_disconnected(struct scsi_qla_host *vha,
|
||||||
|
struct device_reg_24xx __iomem *reg)
|
||||||
|
{
|
||||||
|
uint32_t stat;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
stat = rd_reg_dword(®->host_status);
|
||||||
|
if (stat == 0xffffffff) {
|
||||||
|
ql_log(ql_log_info, vha, 0x8041,
|
||||||
|
"detected PCI disconnect.\n");
|
||||||
|
qla_schedule_eeh_work(vha);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -1644,8 +1644,14 @@ qla24xx_start_scsi(srb_t *sp)
|
|||||||
goto queuing_error;
|
goto queuing_error;
|
||||||
|
|
||||||
if (req->cnt < (req_cnt + 2)) {
|
if (req->cnt < (req_cnt + 2)) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -1836,8 +1842,13 @@ qla24xx_dif_start_scsi(srb_t *sp)
|
|||||||
goto queuing_error;
|
goto queuing_error;
|
||||||
|
|
||||||
if (req->cnt < (req_cnt + 2)) {
|
if (req->cnt < (req_cnt + 2)) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -1911,6 +1922,7 @@ queuing_error:
|
|||||||
|
|
||||||
qla_put_iocbs(sp->qpair, &sp->iores);
|
qla_put_iocbs(sp->qpair, &sp->iores);
|
||||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
|
||||||
return QLA_FUNCTION_FAILED;
|
return QLA_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1978,8 +1990,14 @@ qla2xxx_start_scsi_mq(srb_t *sp)
|
|||||||
goto queuing_error;
|
goto queuing_error;
|
||||||
|
|
||||||
if (req->cnt < (req_cnt + 2)) {
|
if (req->cnt < (req_cnt + 2)) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -2185,8 +2203,14 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
|
|||||||
goto queuing_error;
|
goto queuing_error;
|
||||||
|
|
||||||
if (req->cnt < (req_cnt + 2)) {
|
if (req->cnt < (req_cnt + 2)) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -2263,6 +2287,7 @@ queuing_error:
|
|||||||
|
|
||||||
qla_put_iocbs(sp->qpair, &sp->iores);
|
qla_put_iocbs(sp->qpair, &sp->iores);
|
||||||
spin_unlock_irqrestore(&qpair->qp_lock, flags);
|
spin_unlock_irqrestore(&qpair->qp_lock, flags);
|
||||||
|
|
||||||
return QLA_FUNCTION_FAILED;
|
return QLA_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2307,6 +2332,11 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
|
|||||||
cnt = qla2x00_debounce_register(
|
cnt = qla2x00_debounce_register(
|
||||||
ISP_REQ_Q_OUT(ha, ®->isp));
|
ISP_REQ_Q_OUT(ha, ®->isp));
|
||||||
|
|
||||||
|
if (!qpair->use_shadow_reg && cnt == ISP_REG16_DISCONNECT) {
|
||||||
|
qla_schedule_eeh_work(vha);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -3711,6 +3741,9 @@ qla2x00_start_sp(srb_t *sp)
|
|||||||
void *pkt;
|
void *pkt;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (vha->hw->flags.eeh_busy)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
spin_lock_irqsave(qp->qp_lock_ptr, flags);
|
spin_lock_irqsave(qp->qp_lock_ptr, flags);
|
||||||
pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
|
pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
|
||||||
if (!pkt) {
|
if (!pkt) {
|
||||||
@@ -3928,8 +3961,14 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds)
|
|||||||
|
|
||||||
/* Check for room on request queue. */
|
/* Check for room on request queue. */
|
||||||
if (req->cnt < req_cnt + 2) {
|
if (req->cnt < req_cnt + 2) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
else
|
else
|
||||||
@@ -3968,5 +4007,6 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds)
|
|||||||
qla2x00_start_iocbs(vha, req);
|
qla2x00_start_iocbs(vha, req);
|
||||||
queuing_error:
|
queuing_error:
|
||||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
@@ -269,12 +269,7 @@ qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
|
|||||||
if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
|
if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
|
||||||
!test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
|
!test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
|
||||||
!test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
|
!test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
|
||||||
/*
|
qla_schedule_eeh_work(vha);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
@@ -1643,8 +1638,6 @@ global_port_update:
|
|||||||
case MBA_TEMPERATURE_ALERT:
|
case MBA_TEMPERATURE_ALERT:
|
||||||
ql_dbg(ql_dbg_async, vha, 0x505e,
|
ql_dbg(ql_dbg_async, vha, 0x505e,
|
||||||
"TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
|
"TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
|
||||||
if (mb[1] == 0x12)
|
|
||||||
schedule_work(&ha->board_disable);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBA_TRANS_INSERT:
|
case MBA_TRANS_INSERT:
|
||||||
|
@@ -167,7 +167,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
|||||||
/* check if ISP abort is active and return cmd with timeout */
|
/* check if ISP abort is active and return cmd with timeout */
|
||||||
if ((test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
|
if ((test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
|
||||||
test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
|
test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
|
||||||
test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) &&
|
test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) ||
|
||||||
|
ha->flags.eeh_busy) &&
|
||||||
!is_rom_cmd(mcp->mb[0])) {
|
!is_rom_cmd(mcp->mb[0])) {
|
||||||
ql_log(ql_log_info, vha, 0x1005,
|
ql_log(ql_log_info, vha, 0x1005,
|
||||||
"Cmd 0x%x aborted with timeout since ISP Abort is pending\n",
|
"Cmd 0x%x aborted with timeout since ISP Abort is pending\n",
|
||||||
|
@@ -397,8 +397,13 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
|||||||
}
|
}
|
||||||
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
|
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
|
||||||
if (req->cnt < (req_cnt + 2)) {
|
if (req->cnt < (req_cnt + 2)) {
|
||||||
cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
|
if (IS_SHADOW_REG_CAPABLE(ha)) {
|
||||||
rd_reg_dword_relaxed(req->req_q_out);
|
cnt = *req->out_ptr;
|
||||||
|
} else {
|
||||||
|
cnt = rd_reg_dword_relaxed(req->req_q_out);
|
||||||
|
if (qla2x00_check_reg16_for_disconnect(vha, cnt))
|
||||||
|
goto queuing_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ring_index < cnt)
|
if (req->ring_index < cnt)
|
||||||
req->cnt = cnt - req->ring_index;
|
req->cnt = cnt - req->ring_index;
|
||||||
@@ -535,6 +540,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
|||||||
|
|
||||||
queuing_error:
|
queuing_error:
|
||||||
spin_unlock_irqrestore(&qpair->qp_lock, flags);
|
spin_unlock_irqrestore(&qpair->qp_lock, flags);
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -961,6 +961,13 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
|
|||||||
goto qc24_fail_command;
|
goto qc24_fail_command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!qpair->online) {
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3077,
|
||||||
|
"qpair not online. eeh_busy=%d.\n", ha->flags.eeh_busy);
|
||||||
|
cmd->result = DID_NO_CONNECT << 16;
|
||||||
|
goto qc24_fail_command;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fcport || fcport->deleted) {
|
if (!fcport || fcport->deleted) {
|
||||||
cmd->result = DID_IMM_RETRY << 16;
|
cmd->result = DID_IMM_RETRY << 16;
|
||||||
goto qc24_fail_command;
|
goto qc24_fail_command;
|
||||||
@@ -1190,35 +1197,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
|
|||||||
return return_status;
|
return return_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ISP_REG_DISCONNECT 0xffffffffU
|
|
||||||
/**************************************************************************
|
|
||||||
* qla2x00_isp_reg_stat
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Read the host status register of ISP before aborting the command.
|
|
||||||
*
|
|
||||||
* Input:
|
|
||||||
* ha = pointer to host adapter structure.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* Either true or false.
|
|
||||||
*
|
|
||||||
* Note: Return true if there is register disconnect.
|
|
||||||
**************************************************************************/
|
|
||||||
static inline
|
|
||||||
uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha)
|
|
||||||
{
|
|
||||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
||||||
struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
|
|
||||||
|
|
||||||
if (IS_P3P_TYPE(ha))
|
|
||||||
return ((rd_reg_dword(®82->host_int)) == ISP_REG_DISCONNECT);
|
|
||||||
else
|
|
||||||
return ((rd_reg_dword(®->host_status)) ==
|
|
||||||
ISP_REG_DISCONNECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* qla2xxx_eh_abort
|
* qla2xxx_eh_abort
|
||||||
*
|
*
|
||||||
@@ -1253,6 +1231,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||||||
if (qla2x00_isp_reg_stat(ha)) {
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
ql_log(ql_log_info, vha, 0x8042,
|
ql_log(ql_log_info, vha, 0x8042,
|
||||||
"PCI/Register disconnect, exiting.\n");
|
"PCI/Register disconnect, exiting.\n");
|
||||||
|
qla_pci_set_eeh_busy(vha);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1444,6 +1423,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
|
|||||||
if (qla2x00_isp_reg_stat(ha)) {
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
ql_log(ql_log_info, vha, 0x803e,
|
ql_log(ql_log_info, vha, 0x803e,
|
||||||
"PCI/Register disconnect, exiting.\n");
|
"PCI/Register disconnect, exiting.\n");
|
||||||
|
qla_pci_set_eeh_busy(vha);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1460,6 +1440,7 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
|
|||||||
if (qla2x00_isp_reg_stat(ha)) {
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
ql_log(ql_log_info, vha, 0x803f,
|
ql_log(ql_log_info, vha, 0x803f,
|
||||||
"PCI/Register disconnect, exiting.\n");
|
"PCI/Register disconnect, exiting.\n");
|
||||||
|
qla_pci_set_eeh_busy(vha);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1495,6 +1476,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
|
|||||||
if (qla2x00_isp_reg_stat(ha)) {
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
ql_log(ql_log_info, vha, 0x8040,
|
ql_log(ql_log_info, vha, 0x8040,
|
||||||
"PCI/Register disconnect, exiting.\n");
|
"PCI/Register disconnect, exiting.\n");
|
||||||
|
qla_pci_set_eeh_busy(vha);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1572,7 +1554,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
|
|||||||
if (qla2x00_isp_reg_stat(ha)) {
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
ql_log(ql_log_info, vha, 0x8041,
|
ql_log(ql_log_info, vha, 0x8041,
|
||||||
"PCI/Register disconnect, exiting.\n");
|
"PCI/Register disconnect, exiting.\n");
|
||||||
schedule_work(&ha->board_disable);
|
qla_pci_set_eeh_busy(vha);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6677,6 +6659,9 @@ qla2x00_do_dpc(void *data)
|
|||||||
|
|
||||||
schedule();
|
schedule();
|
||||||
|
|
||||||
|
if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags))
|
||||||
|
qla_pci_set_eeh_busy(base_vha);
|
||||||
|
|
||||||
if (!base_vha->flags.init_done || ha->flags.mbox_busy)
|
if (!base_vha->flags.init_done || ha->flags.mbox_busy)
|
||||||
goto end_loop;
|
goto end_loop;
|
||||||
|
|
||||||
@@ -7384,6 +7369,8 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha)
|
|||||||
int i;
|
int i;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_aer, vha, 0x9000,
|
||||||
|
"%s\n", __func__);
|
||||||
ha->chip_reset++;
|
ha->chip_reset++;
|
||||||
|
|
||||||
ha->base_qpair->chip_reset = ha->chip_reset;
|
ha->base_qpair->chip_reset = ha->chip_reset;
|
||||||
@@ -7393,28 +7380,16 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha)
|
|||||||
ha->base_qpair->chip_reset;
|
ha->base_qpair->chip_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* purge MBox commands */
|
/*
|
||||||
if (atomic_read(&ha->num_pend_mbx_stage3)) {
|
* purge mailbox might take a while. Slot Reset/chip reset
|
||||||
clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
|
* will take care of the purge
|
||||||
complete(&ha->mbx_intr_comp);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
while (atomic_read(&ha->num_pend_mbx_stage3) ||
|
|
||||||
atomic_read(&ha->num_pend_mbx_stage2) ||
|
|
||||||
atomic_read(&ha->num_pend_mbx_stage1)) {
|
|
||||||
msleep(20);
|
|
||||||
i++;
|
|
||||||
if (i > 50)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha->flags.purge_mbox = 0;
|
|
||||||
|
|
||||||
mutex_lock(&ha->mq_lock);
|
mutex_lock(&ha->mq_lock);
|
||||||
|
ha->base_qpair->online = 0;
|
||||||
list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem)
|
list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem)
|
||||||
qpair->online = 0;
|
qpair->online = 0;
|
||||||
|
wmb();
|
||||||
mutex_unlock(&ha->mq_lock);
|
mutex_unlock(&ha->mq_lock);
|
||||||
|
|
||||||
qla2x00_mark_all_devices_lost(vha);
|
qla2x00_mark_all_devices_lost(vha);
|
||||||
@@ -7451,14 +7426,17 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
|||||||
{
|
{
|
||||||
scsi_qla_host_t *vha = pci_get_drvdata(pdev);
|
scsi_qla_host_t *vha = pci_get_drvdata(pdev);
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
pci_ers_result_t ret = PCI_ERS_RESULT_NEED_RESET;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_aer, vha, 0x9000,
|
ql_log(ql_log_warn, vha, 0x9000,
|
||||||
"PCI error detected, state %x.\n", state);
|
"PCI error detected, state %x.\n", state);
|
||||||
|
ha->pci_error_state = QLA_PCI_ERR_DETECTED;
|
||||||
|
|
||||||
if (!atomic_read(&pdev->enable_cnt)) {
|
if (!atomic_read(&pdev->enable_cnt)) {
|
||||||
ql_log(ql_log_info, vha, 0xffff,
|
ql_log(ql_log_info, vha, 0xffff,
|
||||||
"PCI device is disabled,state %x\n", state);
|
"PCI device is disabled,state %x\n", state);
|
||||||
return PCI_ERS_RESULT_NEED_RESET;
|
ret = PCI_ERS_RESULT_NEED_RESET;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -7468,11 +7446,12 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
|||||||
set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags);
|
set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags);
|
||||||
qla2xxx_wake_dpc(vha);
|
qla2xxx_wake_dpc(vha);
|
||||||
}
|
}
|
||||||
return PCI_ERS_RESULT_CAN_RECOVER;
|
ret = PCI_ERS_RESULT_CAN_RECOVER;
|
||||||
|
break;
|
||||||
case pci_channel_io_frozen:
|
case pci_channel_io_frozen:
|
||||||
ha->flags.eeh_busy = 1;
|
qla_pci_set_eeh_busy(vha);
|
||||||
qla_pci_error_cleanup(vha);
|
ret = PCI_ERS_RESULT_NEED_RESET;
|
||||||
return PCI_ERS_RESULT_NEED_RESET;
|
break;
|
||||||
case pci_channel_io_perm_failure:
|
case pci_channel_io_perm_failure:
|
||||||
ha->flags.pci_channel_io_perm_failure = 1;
|
ha->flags.pci_channel_io_perm_failure = 1;
|
||||||
qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
|
qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
|
||||||
@@ -7480,9 +7459,12 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
|||||||
set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags);
|
set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags);
|
||||||
qla2xxx_wake_dpc(vha);
|
qla2xxx_wake_dpc(vha);
|
||||||
}
|
}
|
||||||
return PCI_ERS_RESULT_DISCONNECT;
|
ret = PCI_ERS_RESULT_DISCONNECT;
|
||||||
}
|
}
|
||||||
return PCI_ERS_RESULT_NEED_RESET;
|
out:
|
||||||
|
ql_dbg(ql_dbg_aer, vha, 0x600d,
|
||||||
|
"PCI error detected returning [%x].\n", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pci_ers_result_t
|
static pci_ers_result_t
|
||||||
@@ -7496,6 +7478,10 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
|
|||||||
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
||||||
struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
|
struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
|
||||||
|
|
||||||
|
ql_log(ql_log_warn, base_vha, 0x9000,
|
||||||
|
"mmio enabled\n");
|
||||||
|
|
||||||
|
ha->pci_error_state = QLA_PCI_MMIO_ENABLED;
|
||||||
if (IS_QLA82XX(ha))
|
if (IS_QLA82XX(ha))
|
||||||
return PCI_ERS_RESULT_RECOVERED;
|
return PCI_ERS_RESULT_RECOVERED;
|
||||||
|
|
||||||
@@ -7519,10 +7505,11 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
|
|||||||
ql_log(ql_log_info, base_vha, 0x9003,
|
ql_log(ql_log_info, base_vha, 0x9003,
|
||||||
"RISC paused -- mmio_enabled, Dumping firmware.\n");
|
"RISC paused -- mmio_enabled, Dumping firmware.\n");
|
||||||
qla2xxx_dump_fw(base_vha);
|
qla2xxx_dump_fw(base_vha);
|
||||||
|
}
|
||||||
return PCI_ERS_RESULT_NEED_RESET;
|
/* set PCI_ERS_RESULT_NEED_RESET to trigger call to qla2xxx_pci_slot_reset */
|
||||||
} else
|
ql_dbg(ql_dbg_aer, base_vha, 0x600d,
|
||||||
return PCI_ERS_RESULT_RECOVERED;
|
"mmio enabled returning.\n");
|
||||||
|
return PCI_ERS_RESULT_NEED_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pci_ers_result_t
|
static pci_ers_result_t
|
||||||
@@ -7534,9 +7521,10 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
|
|||||||
int rc;
|
int rc;
|
||||||
struct qla_qpair *qpair = NULL;
|
struct qla_qpair *qpair = NULL;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_aer, base_vha, 0x9004,
|
ql_log(ql_log_warn, base_vha, 0x9004,
|
||||||
"Slot Reset.\n");
|
"Slot Reset.\n");
|
||||||
|
|
||||||
|
ha->pci_error_state = QLA_PCI_SLOT_RESET;
|
||||||
/* Workaround: qla2xxx driver which access hardware earlier
|
/* Workaround: qla2xxx driver which access hardware earlier
|
||||||
* needs error state to be pci_channel_io_online.
|
* needs error state to be pci_channel_io_online.
|
||||||
* Otherwise mailbox command timesout.
|
* Otherwise mailbox command timesout.
|
||||||
@@ -7570,16 +7558,24 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
|
|||||||
qpair->online = 1;
|
qpair->online = 1;
|
||||||
mutex_unlock(&ha->mq_lock);
|
mutex_unlock(&ha->mq_lock);
|
||||||
|
|
||||||
|
ha->flags.eeh_busy = 0;
|
||||||
base_vha->flags.online = 1;
|
base_vha->flags.online = 1;
|
||||||
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
||||||
if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS)
|
ha->isp_ops->abort_isp(base_vha);
|
||||||
ret = PCI_ERS_RESULT_RECOVERED;
|
|
||||||
clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
||||||
|
|
||||||
|
if (qla2x00_isp_reg_stat(ha)) {
|
||||||
|
ha->flags.eeh_busy = 1;
|
||||||
|
qla_pci_error_cleanup(base_vha);
|
||||||
|
ql_log(ql_log_warn, base_vha, 0x9005,
|
||||||
|
"Device unable to recover from PCI error.\n");
|
||||||
|
} else {
|
||||||
|
ret = PCI_ERS_RESULT_RECOVERED;
|
||||||
|
}
|
||||||
|
|
||||||
exit_slot_reset:
|
exit_slot_reset:
|
||||||
ql_dbg(ql_dbg_aer, base_vha, 0x900e,
|
ql_dbg(ql_dbg_aer, base_vha, 0x900e,
|
||||||
"slot_reset return %x.\n", ret);
|
"Slot Reset returning %x.\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -7591,16 +7587,55 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
|
|||||||
struct qla_hw_data *ha = base_vha->hw;
|
struct qla_hw_data *ha = base_vha->hw;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_aer, base_vha, 0x900f,
|
ql_log(ql_log_warn, base_vha, 0x900f,
|
||||||
"pci_resume.\n");
|
"Pci Resume.\n");
|
||||||
|
|
||||||
ha->flags.eeh_busy = 0;
|
|
||||||
|
|
||||||
ret = qla2x00_wait_for_hba_online(base_vha);
|
ret = qla2x00_wait_for_hba_online(base_vha);
|
||||||
if (ret != QLA_SUCCESS) {
|
if (ret != QLA_SUCCESS) {
|
||||||
ql_log(ql_log_fatal, base_vha, 0x9002,
|
ql_log(ql_log_fatal, base_vha, 0x9002,
|
||||||
"The device failed to resume I/O from slot/link_reset.\n");
|
"The device failed to resume I/O from slot/link_reset.\n");
|
||||||
}
|
}
|
||||||
|
ha->pci_error_state = QLA_PCI_RESUME;
|
||||||
|
ql_dbg(ql_dbg_aer, base_vha, 0x600d,
|
||||||
|
"Pci Resume returning.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void qla_pci_set_eeh_busy(struct scsi_qla_host *vha)
|
||||||
|
{
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||||
|
bool do_cleanup = false;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (ha->flags.eeh_busy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&base_vha->work_lock, flags);
|
||||||
|
if (!ha->flags.eeh_busy) {
|
||||||
|
ha->flags.eeh_busy = 1;
|
||||||
|
do_cleanup = true;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&base_vha->work_lock, flags);
|
||||||
|
|
||||||
|
if (do_cleanup)
|
||||||
|
qla_pci_error_cleanup(base_vha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this routine will schedule a task to pause IO from interrupt context
|
||||||
|
* if caller sees a PCIE error event (register read = 0xf's)
|
||||||
|
*/
|
||||||
|
void qla_schedule_eeh_work(struct scsi_qla_host *vha)
|
||||||
|
{
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||||
|
|
||||||
|
if (ha->flags.eeh_busy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags);
|
||||||
|
qla2xxx_wake_dpc(base_vha);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Reference in New Issue
Block a user