aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaurav Kashyap <saurav.kashyap@qlogic.com>2010-12-21 19:00:14 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-12-23 16:40:55 -0500
commit579d12b58abb4bd1161728f0a4a2524258ecf0a3 (patch)
tree53f9ff32d3112b3c850aa51de9f1bbef08fbf996
parent5f7bb3a439ce51ae8b92ca1dc93b91712224b69a (diff)
[SCSI] qla2xxx: Added support for quiescence mode for ISP82xx.
Support is added for quiescence mode. This feature is for P3P adapters. Any of the functions can put the firmware into quiescence state. All the others have to ack that request. During quiescence mode current commands are processed and all the new incoming I/Os are blocked. Loop resync is performed after firmware comes out of quiescence state. Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com> Signed-off-by: Madhuranath Iyengar <Madhu.Iyengar@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c67
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c132
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c24
5 files changed, 224 insertions, 6 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 9ce539d4557e..6168628bd6b9 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2425,6 +2425,8 @@ struct qla_hw_data {
2425 uint32_t disable_msix_handshake :1; 2425 uint32_t disable_msix_handshake :1;
2426 uint32_t fcp_prio_enabled :1; 2426 uint32_t fcp_prio_enabled :1;
2427 uint32_t fw_hung :1; 2427 uint32_t fw_hung :1;
2428 uint32_t quiesce_owner:1;
2429 /* 29 bits */
2428 } flags; 2430 } flags;
2429 2431
2430 /* This spinlock is used to protect "io transactions", you must 2432 /* This spinlock is used to protect "io transactions", you must
@@ -2863,6 +2865,7 @@ typedef struct scsi_qla_host {
2863#define ISP_UNRECOVERABLE 17 2865#define ISP_UNRECOVERABLE 17
2864#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ 2866#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
2865#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ 2867#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
2868#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */
2866 2869
2867 uint32_t device_flags; 2870 uint32_t device_flags;
2868#define SWITCH_FOUND BIT_0 2871#define SWITCH_FOUND BIT_0
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 9382a816c133..1370f05ae330 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -36,6 +36,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
36extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); 36extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
37extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); 37extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
38 38
39extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
39extern int qla2x00_loop_resync(scsi_qla_host_t *); 40extern int qla2x00_loop_resync(scsi_qla_host_t *);
40 41
41extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); 42extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
@@ -45,6 +46,7 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *);
45 46
46extern int qla2x00_abort_isp(scsi_qla_host_t *); 47extern int qla2x00_abort_isp(scsi_qla_host_t *);
47extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); 48extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
49extern void qla82xx_quiescent_state_cleanup(scsi_qla_host_t *);
48 50
49extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); 51extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
50 52
@@ -549,9 +551,11 @@ extern void qla82xx_rom_unlock(struct qla_hw_data *);
549 551
550/* ISP 8021 IDC */ 552/* ISP 8021 IDC */
551extern void qla82xx_clear_drv_active(struct qla_hw_data *); 553extern void qla82xx_clear_drv_active(struct qla_hw_data *);
554extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t);
552extern int qla82xx_idc_lock(struct qla_hw_data *); 555extern int qla82xx_idc_lock(struct qla_hw_data *);
553extern void qla82xx_idc_unlock(struct qla_hw_data *); 556extern void qla82xx_idc_unlock(struct qla_hw_data *);
554extern int qla82xx_device_state_handler(scsi_qla_host_t *); 557extern int qla82xx_device_state_handler(scsi_qla_host_t *);
558extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
555 559
556extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, 560extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
557 size_t, char *); 561 size_t, char *);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 259f51137493..6f7cf3970383 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3844,6 +3844,37 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
3844 return (rval); 3844 return (rval);
3845} 3845}
3846 3846
3847/*
3848* qla2x00_perform_loop_resync
3849* Description: This function will set the appropriate flags and call
3850* qla2x00_loop_resync. If successful loop will be resynced
3851* Arguments : scsi_qla_host_t pointer
3852* returm : Success or Failure
3853*/
3854
3855int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
3856{
3857 int32_t rval = 0;
3858
3859 if (!test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) {
3860 /*Configure the flags so that resync happens properly*/
3861 atomic_set(&ha->loop_down_timer, 0);
3862 if (!(ha->device_flags & DFLG_NO_CABLE)) {
3863 atomic_set(&ha->loop_state, LOOP_UP);
3864 set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
3865 set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
3866 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
3867
3868 rval = qla2x00_loop_resync(ha);
3869 } else
3870 atomic_set(&ha->loop_state, LOOP_DEAD);
3871
3872 clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
3873 }
3874
3875 return rval;
3876}
3877
3847void 3878void
3848qla2x00_update_fcports(scsi_qla_host_t *base_vha) 3879qla2x00_update_fcports(scsi_qla_host_t *base_vha)
3849{ 3880{
@@ -3871,11 +3902,43 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
3871 spin_unlock_irqrestore(&ha->vport_slock, flags); 3902 spin_unlock_irqrestore(&ha->vport_slock, flags);
3872} 3903}
3873 3904
3905/*
3906* qla82xx_quiescent_state_cleanup
3907* Description: This function will block the new I/Os
3908* Its not aborting any I/Os as context
3909* is not destroyed during quiescence
3910* Arguments: scsi_qla_host_t
3911* return : void
3912*/
3913void
3914qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
3915{
3916 struct qla_hw_data *ha = vha->hw;
3917 struct scsi_qla_host *vp;
3918
3919 qla_printk(KERN_INFO, ha,
3920 "Performing ISP error recovery - ha= %p.\n", ha);
3921
3922 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
3923 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
3924 atomic_set(&vha->loop_state, LOOP_DOWN);
3925 qla2x00_mark_all_devices_lost(vha, 0);
3926 list_for_each_entry(vp, &ha->vp_list, list)
3927 qla2x00_mark_all_devices_lost(vha, 0);
3928 } else {
3929 if (!atomic_read(&vha->loop_down_timer))
3930 atomic_set(&vha->loop_down_timer,
3931 LOOP_DOWN_TIME);
3932 }
3933 /* Wait for pending cmds to complete */
3934 qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST);
3935}
3936
3874void 3937void
3875qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) 3938qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
3876{ 3939{
3877 struct qla_hw_data *ha = vha->hw; 3940 struct qla_hw_data *ha = vha->hw;
3878 struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); 3941 struct scsi_qla_host *vp;
3879 unsigned long flags; 3942 unsigned long flags;
3880 3943
3881 vha->flags.online = 0; 3944 vha->flags.online = 0;
@@ -3896,7 +3959,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
3896 qla2x00_mark_all_devices_lost(vha, 0); 3959 qla2x00_mark_all_devices_lost(vha, 0);
3897 3960
3898 spin_lock_irqsave(&ha->vport_slock, flags); 3961 spin_lock_irqsave(&ha->vport_slock, flags);
3899 list_for_each_entry(vp, &base_vha->hw->vp_list, list) { 3962 list_for_each_entry(vp, &ha->vp_list, list) {
3900 atomic_inc(&vp->vref_count); 3963 atomic_inc(&vp->vref_count);
3901 spin_unlock_irqrestore(&ha->vport_slock, flags); 3964 spin_unlock_irqrestore(&ha->vport_slock, flags);
3902 3965
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index ae2acacc0003..9175e847b93a 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2343,6 +2343,17 @@ qla82xx_set_qsnt_ready(struct qla_hw_data *ha)
2343 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); 2343 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
2344} 2344}
2345 2345
2346void
2347qla82xx_clear_qsnt_ready(scsi_qla_host_t *vha)
2348{
2349 struct qla_hw_data *ha = vha->hw;
2350 uint32_t qsnt_state;
2351
2352 qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
2353 qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
2354 qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
2355}
2356
2346static int 2357static int
2347qla82xx_load_fw(scsi_qla_host_t *vha) 2358qla82xx_load_fw(scsi_qla_host_t *vha)
2348{ 2359{
@@ -3261,6 +3272,104 @@ dev_ready:
3261 return QLA_SUCCESS; 3272 return QLA_SUCCESS;
3262} 3273}
3263 3274
3275/*
3276* qla82xx_need_qsnt_handler
3277* Code to start quiescence sequence
3278*
3279* Note:
3280* IDC lock must be held upon entry
3281*
3282* Return: void
3283*/
3284
3285static void
3286qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
3287{
3288 struct qla_hw_data *ha = vha->hw;
3289 uint32_t dev_state, drv_state, drv_active;
3290 unsigned long reset_timeout;
3291
3292 if (vha->flags.online) {
3293 /*Block any further I/O and wait for pending cmnds to complete*/
3294 qla82xx_quiescent_state_cleanup(vha);
3295 }
3296
3297 /* Set the quiescence ready bit */
3298 qla82xx_set_qsnt_ready(ha);
3299
3300 /*wait for 30 secs for other functions to ack */
3301 reset_timeout = jiffies + (30 * HZ);
3302
3303 drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
3304 drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
3305 /* Its 2 that is written when qsnt is acked, moving one bit */
3306 drv_active = drv_active << 0x01;
3307
3308 while (drv_state != drv_active) {
3309
3310 if (time_after_eq(jiffies, reset_timeout)) {
3311 /* quiescence timeout, other functions didn't ack
3312 * changing the state to DEV_READY
3313 */
3314 qla_printk(KERN_INFO, ha,
3315 "%s: QUIESCENT TIMEOUT\n", QLA2XXX_DRIVER_NAME);
3316 qla_printk(KERN_INFO, ha,
3317 "DRV_ACTIVE:%d DRV_STATE:%d\n", drv_active,
3318 drv_state);
3319 qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
3320 QLA82XX_DEV_READY);
3321 qla_printk(KERN_INFO, ha,
3322 "HW State: DEV_READY\n");
3323 qla82xx_idc_unlock(ha);
3324 qla2x00_perform_loop_resync(vha);
3325 qla82xx_idc_lock(ha);
3326
3327 qla82xx_clear_qsnt_ready(vha);
3328 return;
3329 }
3330
3331 qla82xx_idc_unlock(ha);
3332 msleep(1000);
3333 qla82xx_idc_lock(ha);
3334
3335 drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
3336 drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
3337 drv_active = drv_active << 0x01;
3338 }
3339 dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
3340 /* everyone acked so set the state to DEV_QUIESCENCE */
3341 if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
3342 qla_printk(KERN_INFO, ha, "HW State: DEV_QUIESCENT\n");
3343 qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
3344 }
3345}
3346
3347/*
3348* qla82xx_wait_for_state_change
3349* Wait for device state to change from given current state
3350*
3351* Note:
3352* IDC lock must not be held upon entry
3353*
3354* Return:
3355* Changed device state.
3356*/
3357uint32_t
3358qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
3359{
3360 struct qla_hw_data *ha = vha->hw;
3361 uint32_t dev_state;
3362
3363 do {
3364 msleep(1000);
3365 qla82xx_idc_lock(ha);
3366 dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
3367 qla82xx_idc_unlock(ha);
3368 } while (dev_state == curr_state);
3369
3370 return dev_state;
3371}
3372
3264static void 3373static void
3265qla82xx_dev_failed_handler(scsi_qla_host_t *vha) 3374qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
3266{ 3375{
@@ -3443,11 +3552,25 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
3443 qla82xx_need_reset_handler(vha); 3552 qla82xx_need_reset_handler(vha);
3444 break; 3553 break;
3445 case QLA82XX_DEV_NEED_QUIESCENT: 3554 case QLA82XX_DEV_NEED_QUIESCENT:
3446 qla82xx_set_qsnt_ready(ha); 3555 qla82xx_need_qsnt_handler(vha);
3556 /* Reset timeout value after quiescence handler */
3557 dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
3558 * HZ);
3559 break;
3447 case QLA82XX_DEV_QUIESCENT: 3560 case QLA82XX_DEV_QUIESCENT:
3561 /* Owner will exit and other will wait for the state
3562 * to get changed
3563 */
3564 if (ha->flags.quiesce_owner)
3565 goto exit;
3566
3448 qla82xx_idc_unlock(ha); 3567 qla82xx_idc_unlock(ha);
3449 msleep(1000); 3568 msleep(1000);
3450 qla82xx_idc_lock(ha); 3569 qla82xx_idc_lock(ha);
3570
3571 /* Reset timeout value after quiescence handler */
3572 dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
3573 * HZ);
3451 break; 3574 break;
3452 case QLA82XX_DEV_FAILED: 3575 case QLA82XX_DEV_FAILED:
3453 qla82xx_dev_failed_handler(vha); 3576 qla82xx_dev_failed_handler(vha);
@@ -3490,6 +3613,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
3490 &ha->mbx_cmd_flags)) 3613 &ha->mbx_cmd_flags))
3491 complete(&ha->mbx_intr_comp); 3614 complete(&ha->mbx_intr_comp);
3492 } 3615 }
3616 } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
3617 !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
3618 DEBUG(qla_printk(KERN_INFO, ha,
3619 "scsi(%ld) %s - detected quiescence needed\n",
3620 vha->host_no, __func__));
3621 set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
3622 qla2xxx_wake_dpc(vha);
3493 } else { 3623 } else {
3494 qla82xx_check_fw_alive(vha); 3624 qla82xx_check_fw_alive(vha);
3495 } 3625 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2c0876c81a3f..df2c1e7ab652 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3386,6 +3386,21 @@ qla2x00_do_dpc(void *data)
3386 clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); 3386 clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
3387 } 3387 }
3388 3388
3389 if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
3390 DEBUG(printk(KERN_INFO "scsi(%ld): dpc: sched "
3391 "qla2x00_quiesce_needed ha = %p\n",
3392 base_vha->host_no, ha));
3393 qla82xx_device_state_handler(base_vha);
3394 clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
3395 if (!ha->flags.quiesce_owner) {
3396 qla2x00_perform_loop_resync(base_vha);
3397
3398 qla82xx_idc_lock(ha);
3399 qla82xx_clear_qsnt_ready(base_vha);
3400 qla82xx_idc_unlock(ha);
3401 }
3402 }
3403
3389 if (test_and_clear_bit(RESET_MARKER_NEEDED, 3404 if (test_and_clear_bit(RESET_MARKER_NEEDED,
3390 &base_vha->dpc_flags) && 3405 &base_vha->dpc_flags) &&
3391 (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) { 3406 (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
@@ -3589,13 +3604,16 @@ qla2x00_timer(scsi_qla_host_t *vha)
3589 return; 3604 return;
3590 } 3605 }
3591 3606
3592 if (IS_QLA82XX(ha))
3593 qla82xx_watchdog(vha);
3594
3595 /* Hardware read to raise pending EEH errors during mailbox waits. */ 3607 /* Hardware read to raise pending EEH errors during mailbox waits. */
3596 if (!pci_channel_offline(ha->pdev)) 3608 if (!pci_channel_offline(ha->pdev))
3597 pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 3609 pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
3598 3610
3611 if (IS_QLA82XX(ha)) {
3612 if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags))
3613 start_dpc++;
3614 qla82xx_watchdog(vha);
3615 }
3616
3599 /* Loop down handler. */ 3617 /* Loop down handler. */
3600 if (atomic_read(&vha->loop_down_timer) > 0 && 3618 if (atomic_read(&vha->loop_down_timer) > 0 &&
3601 !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) 3619 !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))