diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2009-12-16 00:29:46 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-30 12:09:49 -0500 |
commit | 858808019313f217d63ec4ad26686e6fb7b08c19 (patch) | |
tree | c54623c8b4154a23ddb679c76819e3b32b6638b6 /drivers/scsi/qla2xxx/qla_os.c | |
parent | 5c66f5d193f68c2a7da0f2ad3535ed30ab14307b (diff) |
[SCSI] qla2xxx: Extend base EEH support in qla2xxx.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 83 |
1 files changed, 75 insertions, 8 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2f873d237325..1ab358210c6a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -475,11 +475,11 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
475 | srb_t *sp; | 475 | srb_t *sp; |
476 | int rval; | 476 | int rval; |
477 | 477 | ||
478 | if (unlikely(pci_channel_offline(ha->pdev))) { | 478 | if (ha->flags.eeh_busy) { |
479 | if (ha->pdev->error_state == pci_channel_io_frozen) | 479 | if (ha->flags.pci_channel_io_perm_failure) |
480 | cmd->result = DID_REQUEUE << 16; | ||
481 | else | ||
482 | cmd->result = DID_NO_CONNECT << 16; | 480 | cmd->result = DID_NO_CONNECT << 16; |
481 | else | ||
482 | cmd->result = DID_REQUEUE << 16; | ||
483 | goto qc24_fail_command; | 483 | goto qc24_fail_command; |
484 | } | 484 | } |
485 | 485 | ||
@@ -552,8 +552,15 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) | |||
552 | #define ABORT_POLLING_PERIOD 1000 | 552 | #define ABORT_POLLING_PERIOD 1000 |
553 | #define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) | 553 | #define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) |
554 | unsigned long wait_iter = ABORT_WAIT_ITER; | 554 | unsigned long wait_iter = ABORT_WAIT_ITER; |
555 | scsi_qla_host_t *vha = shost_priv(cmd->device->host); | ||
556 | struct qla_hw_data *ha = vha->hw; | ||
555 | int ret = QLA_SUCCESS; | 557 | int ret = QLA_SUCCESS; |
556 | 558 | ||
559 | if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) { | ||
560 | DEBUG17(qla_printk(KERN_WARNING, ha, "return:eh_wait\n")); | ||
561 | return ret; | ||
562 | } | ||
563 | |||
557 | while (CMD_SP(cmd) && wait_iter--) { | 564 | while (CMD_SP(cmd) && wait_iter--) { |
558 | msleep(ABORT_POLLING_PERIOD); | 565 | msleep(ABORT_POLLING_PERIOD); |
559 | } | 566 | } |
@@ -2174,6 +2181,24 @@ qla2x00_free_device(scsi_qla_host_t *vha) | |||
2174 | { | 2181 | { |
2175 | struct qla_hw_data *ha = vha->hw; | 2182 | struct qla_hw_data *ha = vha->hw; |
2176 | 2183 | ||
2184 | qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); | ||
2185 | |||
2186 | /* Disable timer */ | ||
2187 | if (vha->timer_active) | ||
2188 | qla2x00_stop_timer(vha); | ||
2189 | |||
2190 | /* Kill the kernel thread for this host */ | ||
2191 | if (ha->dpc_thread) { | ||
2192 | struct task_struct *t = ha->dpc_thread; | ||
2193 | |||
2194 | /* | ||
2195 | * qla2xxx_wake_dpc checks for ->dpc_thread | ||
2196 | * so we need to zero it out. | ||
2197 | */ | ||
2198 | ha->dpc_thread = NULL; | ||
2199 | kthread_stop(t); | ||
2200 | } | ||
2201 | |||
2177 | qla25xx_delete_queues(vha); | 2202 | qla25xx_delete_queues(vha); |
2178 | 2203 | ||
2179 | if (ha->flags.fce_enabled) | 2204 | if (ha->flags.fce_enabled) |
@@ -2185,6 +2210,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) | |||
2185 | /* Stop currently executing firmware. */ | 2210 | /* Stop currently executing firmware. */ |
2186 | qla2x00_try_to_stop_firmware(vha); | 2211 | qla2x00_try_to_stop_firmware(vha); |
2187 | 2212 | ||
2213 | vha->flags.online = 0; | ||
2214 | |||
2188 | /* turn-off interrupts on the card */ | 2215 | /* turn-off interrupts on the card */ |
2189 | if (ha->interrupts_on) | 2216 | if (ha->interrupts_on) |
2190 | ha->isp_ops->disable_intrs(ha); | 2217 | ha->isp_ops->disable_intrs(ha); |
@@ -2859,6 +2886,13 @@ qla2x00_do_dpc(void *data) | |||
2859 | if (!base_vha->flags.init_done) | 2886 | if (!base_vha->flags.init_done) |
2860 | continue; | 2887 | continue; |
2861 | 2888 | ||
2889 | if (ha->flags.eeh_busy) { | ||
2890 | DEBUG17(qla_printk(KERN_WARNING, ha, | ||
2891 | "qla2x00_do_dpc: dpc_flags: %lx\n", | ||
2892 | base_vha->dpc_flags)); | ||
2893 | continue; | ||
2894 | } | ||
2895 | |||
2862 | DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no)); | 2896 | DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no)); |
2863 | 2897 | ||
2864 | ha->dpc_active = 1; | 2898 | ha->dpc_active = 1; |
@@ -3049,8 +3083,13 @@ qla2x00_timer(scsi_qla_host_t *vha) | |||
3049 | int index; | 3083 | int index; |
3050 | srb_t *sp; | 3084 | srb_t *sp; |
3051 | int t; | 3085 | int t; |
3086 | uint16_t w; | ||
3052 | struct qla_hw_data *ha = vha->hw; | 3087 | struct qla_hw_data *ha = vha->hw; |
3053 | struct req_que *req; | 3088 | struct req_que *req; |
3089 | |||
3090 | /* Hardware read to raise pending EEH errors during mailbox waits. */ | ||
3091 | if (!pci_channel_offline(ha->pdev)) | ||
3092 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); | ||
3054 | /* | 3093 | /* |
3055 | * Ports - Port down timer. | 3094 | * Ports - Port down timer. |
3056 | * | 3095 | * |
@@ -3252,16 +3291,23 @@ qla2x00_release_firmware(void) | |||
3252 | static pci_ers_result_t | 3291 | static pci_ers_result_t |
3253 | qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | 3292 | qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) |
3254 | { | 3293 | { |
3255 | scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); | 3294 | scsi_qla_host_t *vha = pci_get_drvdata(pdev); |
3295 | struct qla_hw_data *ha = vha->hw; | ||
3296 | |||
3297 | DEBUG2(qla_printk(KERN_WARNING, ha, "error_detected:state %x\n", | ||
3298 | state)); | ||
3256 | 3299 | ||
3257 | switch (state) { | 3300 | switch (state) { |
3258 | case pci_channel_io_normal: | 3301 | case pci_channel_io_normal: |
3302 | ha->flags.eeh_busy = 0; | ||
3259 | return PCI_ERS_RESULT_CAN_RECOVER; | 3303 | return PCI_ERS_RESULT_CAN_RECOVER; |
3260 | case pci_channel_io_frozen: | 3304 | case pci_channel_io_frozen: |
3305 | ha->flags.eeh_busy = 1; | ||
3261 | pci_disable_device(pdev); | 3306 | pci_disable_device(pdev); |
3262 | return PCI_ERS_RESULT_NEED_RESET; | 3307 | return PCI_ERS_RESULT_NEED_RESET; |
3263 | case pci_channel_io_perm_failure: | 3308 | case pci_channel_io_perm_failure: |
3264 | qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); | 3309 | ha->flags.pci_channel_io_perm_failure = 1; |
3310 | qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); | ||
3265 | return PCI_ERS_RESULT_DISCONNECT; | 3311 | return PCI_ERS_RESULT_DISCONNECT; |
3266 | } | 3312 | } |
3267 | return PCI_ERS_RESULT_NEED_RESET; | 3313 | return PCI_ERS_RESULT_NEED_RESET; |
@@ -3312,6 +3358,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3312 | struct qla_hw_data *ha = base_vha->hw; | 3358 | struct qla_hw_data *ha = base_vha->hw; |
3313 | int rc; | 3359 | int rc; |
3314 | 3360 | ||
3361 | DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n")); | ||
3362 | |||
3315 | if (ha->mem_only) | 3363 | if (ha->mem_only) |
3316 | rc = pci_enable_device_mem(pdev); | 3364 | rc = pci_enable_device_mem(pdev); |
3317 | else | 3365 | else |
@@ -3320,19 +3368,33 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3320 | if (rc) { | 3368 | if (rc) { |
3321 | qla_printk(KERN_WARNING, ha, | 3369 | qla_printk(KERN_WARNING, ha, |
3322 | "Can't re-enable PCI device after reset.\n"); | 3370 | "Can't re-enable PCI device after reset.\n"); |
3323 | |||
3324 | return ret; | 3371 | return ret; |
3325 | } | 3372 | } |
3326 | pci_set_master(pdev); | ||
3327 | 3373 | ||
3328 | if (ha->isp_ops->pci_config(base_vha)) | 3374 | if (ha->isp_ops->pci_config(base_vha)) |
3329 | return ret; | 3375 | return ret; |
3330 | 3376 | ||
3377 | #ifdef QL_DEBUG_LEVEL_17 | ||
3378 | { | ||
3379 | uint8_t b; | ||
3380 | uint32_t i; | ||
3381 | |||
3382 | printk("slot_reset_1: "); | ||
3383 | for (i = 0; i < 256; i++) { | ||
3384 | pci_read_config_byte(ha->pdev, i, &b); | ||
3385 | printk("%s%02x", (i%16) ? " " : "\n", b); | ||
3386 | } | ||
3387 | printk("\n"); | ||
3388 | } | ||
3389 | #endif | ||
3331 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 3390 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
3332 | if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) | 3391 | if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) |
3333 | ret = PCI_ERS_RESULT_RECOVERED; | 3392 | ret = PCI_ERS_RESULT_RECOVERED; |
3334 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 3393 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
3335 | 3394 | ||
3395 | DEBUG17(qla_printk(KERN_WARNING, ha, | ||
3396 | "slot_reset-return:ret=%x\n", ret)); | ||
3397 | |||
3336 | return ret; | 3398 | return ret; |
3337 | } | 3399 | } |
3338 | 3400 | ||
@@ -3343,12 +3405,17 @@ qla2xxx_pci_resume(struct pci_dev *pdev) | |||
3343 | struct qla_hw_data *ha = base_vha->hw; | 3405 | struct qla_hw_data *ha = base_vha->hw; |
3344 | int ret; | 3406 | int ret; |
3345 | 3407 | ||
3408 | DEBUG17(qla_printk(KERN_WARNING, ha, "pci_resume\n")); | ||
3409 | |||
3346 | ret = qla2x00_wait_for_hba_online(base_vha); | 3410 | ret = qla2x00_wait_for_hba_online(base_vha); |
3347 | if (ret != QLA_SUCCESS) { | 3411 | if (ret != QLA_SUCCESS) { |
3348 | qla_printk(KERN_ERR, ha, | 3412 | qla_printk(KERN_ERR, ha, |
3349 | "the device failed to resume I/O " | 3413 | "the device failed to resume I/O " |
3350 | "from slot/link_reset"); | 3414 | "from slot/link_reset"); |
3351 | } | 3415 | } |
3416 | |||
3417 | ha->flags.eeh_busy = 0; | ||
3418 | |||
3352 | pci_cleanup_aer_uncorrect_error_status(pdev); | 3419 | pci_cleanup_aer_uncorrect_error_status(pdev); |
3353 | } | 3420 | } |
3354 | 3421 | ||