Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 226867
b: refs/heads/master
c: 579d12b
h: refs/heads/master
i:
  226865: f5b2381
  226863: 3e9f4f0
v: v3
  • Loading branch information
Saurav Kashyap authored and James Bottomley committed Dec 23, 2010
1 parent 50afe4e commit 24c8ec1
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5f7bb3a439ce51ae8b92ca1dc93b91712224b69a
refs/heads/master: 579d12b58abb4bd1161728f0a4a2524258ecf0a3
3 changes: 3 additions & 0 deletions trunk/drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -2425,6 +2425,8 @@ struct qla_hw_data {
uint32_t disable_msix_handshake :1;
uint32_t fcp_prio_enabled :1;
uint32_t fw_hung :1;
uint32_t quiesce_owner:1;
/* 29 bits */
} flags;

/* This spinlock is used to protect "io transactions", you must
Expand Down Expand Up @@ -2863,6 +2865,7 @@ typedef struct scsi_qla_host {
#define ISP_UNRECOVERABLE 17
#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */

uint32_t device_flags;
#define SWITCH_FOUND BIT_0
Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/scsi/qla2xxx/qla_gbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);

extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
extern int qla2x00_loop_resync(scsi_qla_host_t *);

extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
Expand All @@ -45,6 +46,7 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *);

extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
extern void qla82xx_quiescent_state_cleanup(scsi_qla_host_t *);

extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);

Expand Down Expand Up @@ -549,9 +551,11 @@ extern void qla82xx_rom_unlock(struct qla_hw_data *);

/* ISP 8021 IDC */
extern void qla82xx_clear_drv_active(struct qla_hw_data *);
extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t);
extern int qla82xx_idc_lock(struct qla_hw_data *);
extern void qla82xx_idc_unlock(struct qla_hw_data *);
extern int qla82xx_device_state_handler(scsi_qla_host_t *);
extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);

extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
size_t, char *);
Expand Down
67 changes: 65 additions & 2 deletions trunk/drivers/scsi/qla2xxx/qla_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -3844,6 +3844,37 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
return (rval);
}

/*
* qla2x00_perform_loop_resync
* Description: This function will set the appropriate flags and call
* qla2x00_loop_resync. If successful loop will be resynced
* Arguments : scsi_qla_host_t pointer
* returm : Success or Failure
*/

int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
{
int32_t rval = 0;

if (!test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) {
/*Configure the flags so that resync happens properly*/
atomic_set(&ha->loop_down_timer, 0);
if (!(ha->device_flags & DFLG_NO_CABLE)) {
atomic_set(&ha->loop_state, LOOP_UP);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);

rval = qla2x00_loop_resync(ha);
} else
atomic_set(&ha->loop_state, LOOP_DEAD);

clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}

return rval;
}

void
qla2x00_update_fcports(scsi_qla_host_t *base_vha)
{
Expand Down Expand Up @@ -3871,11 +3902,43 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
spin_unlock_irqrestore(&ha->vport_slock, flags);
}

/*
* qla82xx_quiescent_state_cleanup
* Description: This function will block the new I/Os
* Its not aborting any I/Os as context
* is not destroyed during quiescence
* Arguments: scsi_qla_host_t
* return : void
*/
void
qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *vp;

qla_printk(KERN_INFO, ha,
"Performing ISP error recovery - ha= %p.\n", ha);

atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha, 0);
list_for_each_entry(vp, &ha->vp_list, list)
qla2x00_mark_all_devices_lost(vha, 0);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
LOOP_DOWN_TIME);
}
/* Wait for pending cmds to complete */
qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST);
}

void
qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
struct scsi_qla_host *vp;
unsigned long flags;

vha->flags.online = 0;
Expand All @@ -3896,7 +3959,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
qla2x00_mark_all_devices_lost(vha, 0);

spin_lock_irqsave(&ha->vport_slock, flags);
list_for_each_entry(vp, &base_vha->hw->vp_list, list) {
list_for_each_entry(vp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);

Expand Down
132 changes: 131 additions & 1 deletion trunk/drivers/scsi/qla2xxx/qla_nx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2343,6 +2343,17 @@ qla82xx_set_qsnt_ready(struct qla_hw_data *ha)
qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
}

void
qla82xx_clear_qsnt_ready(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
uint32_t qsnt_state;

qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
}

static int
qla82xx_load_fw(scsi_qla_host_t *vha)
{
Expand Down Expand Up @@ -3261,6 +3272,104 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha)
return QLA_SUCCESS;
}

/*
* qla82xx_need_qsnt_handler
* Code to start quiescence sequence
*
* Note:
* IDC lock must be held upon entry
*
* Return: void
*/

static void
qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
uint32_t dev_state, drv_state, drv_active;
unsigned long reset_timeout;

if (vha->flags.online) {
/*Block any further I/O and wait for pending cmnds to complete*/
qla82xx_quiescent_state_cleanup(vha);
}

/* Set the quiescence ready bit */
qla82xx_set_qsnt_ready(ha);

/*wait for 30 secs for other functions to ack */
reset_timeout = jiffies + (30 * HZ);

drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
/* Its 2 that is written when qsnt is acked, moving one bit */
drv_active = drv_active << 0x01;

while (drv_state != drv_active) {

if (time_after_eq(jiffies, reset_timeout)) {
/* quiescence timeout, other functions didn't ack
* changing the state to DEV_READY
*/
qla_printk(KERN_INFO, ha,
"%s: QUIESCENT TIMEOUT\n", QLA2XXX_DRIVER_NAME);
qla_printk(KERN_INFO, ha,
"DRV_ACTIVE:%d DRV_STATE:%d\n", drv_active,
drv_state);
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
QLA82XX_DEV_READY);
qla_printk(KERN_INFO, ha,
"HW State: DEV_READY\n");
qla82xx_idc_unlock(ha);
qla2x00_perform_loop_resync(vha);
qla82xx_idc_lock(ha);

qla82xx_clear_qsnt_ready(vha);
return;
}

qla82xx_idc_unlock(ha);
msleep(1000);
qla82xx_idc_lock(ha);

drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
drv_active = drv_active << 0x01;
}
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
/* everyone acked so set the state to DEV_QUIESCENCE */
if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
qla_printk(KERN_INFO, ha, "HW State: DEV_QUIESCENT\n");
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
}
}

/*
* qla82xx_wait_for_state_change
* Wait for device state to change from given current state
*
* Note:
* IDC lock must not be held upon entry
*
* Return:
* Changed device state.
*/
uint32_t
qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
{
struct qla_hw_data *ha = vha->hw;
uint32_t dev_state;

do {
msleep(1000);
qla82xx_idc_lock(ha);
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
qla82xx_idc_unlock(ha);
} while (dev_state == curr_state);

return dev_state;
}

static void
qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
{
Expand Down Expand Up @@ -3443,11 +3552,25 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
qla82xx_need_reset_handler(vha);
break;
case QLA82XX_DEV_NEED_QUIESCENT:
qla82xx_set_qsnt_ready(ha);
qla82xx_need_qsnt_handler(vha);
/* Reset timeout value after quiescence handler */
dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
* HZ);
break;
case QLA82XX_DEV_QUIESCENT:
/* Owner will exit and other will wait for the state
* to get changed
*/
if (ha->flags.quiesce_owner)
goto exit;

qla82xx_idc_unlock(ha);
msleep(1000);
qla82xx_idc_lock(ha);

/* Reset timeout value after quiescence handler */
dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
* HZ);
break;
case QLA82XX_DEV_FAILED:
qla82xx_dev_failed_handler(vha);
Expand Down Expand Up @@ -3490,6 +3613,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
&ha->mbx_cmd_flags))
complete(&ha->mbx_intr_comp);
}
} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
!test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
DEBUG(qla_printk(KERN_INFO, ha,
"scsi(%ld) %s - detected quiescence needed\n",
vha->host_no, __func__));
set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
} else {
qla82xx_check_fw_alive(vha);
}
Expand Down
24 changes: 21 additions & 3 deletions trunk/drivers/scsi/qla2xxx/qla_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -3386,6 +3386,21 @@ qla2x00_do_dpc(void *data)
clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
}

if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
DEBUG(printk(KERN_INFO "scsi(%ld): dpc: sched "
"qla2x00_quiesce_needed ha = %p\n",
base_vha->host_no, ha));
qla82xx_device_state_handler(base_vha);
clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
if (!ha->flags.quiesce_owner) {
qla2x00_perform_loop_resync(base_vha);

qla82xx_idc_lock(ha);
qla82xx_clear_qsnt_ready(base_vha);
qla82xx_idc_unlock(ha);
}
}

if (test_and_clear_bit(RESET_MARKER_NEEDED,
&base_vha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
Expand Down Expand Up @@ -3589,13 +3604,16 @@ qla2x00_timer(scsi_qla_host_t *vha)
return;
}

if (IS_QLA82XX(ha))
qla82xx_watchdog(vha);

/* Hardware read to raise pending EEH errors during mailbox waits. */
if (!pci_channel_offline(ha->pdev))
pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);

if (IS_QLA82XX(ha)) {
if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags))
start_dpc++;
qla82xx_watchdog(vha);
}

/* Loop down handler. */
if (atomic_read(&vha->loop_down_timer) > 0 &&
!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
Expand Down

0 comments on commit 24c8ec1

Please sign in to comment.