diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 90 |
1 files changed, 82 insertions, 8 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2f873d237325..209f50e788a1 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 | } |
@@ -1810,6 +1817,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1810 | 1817 | ||
1811 | /* Set ISP-type information. */ | 1818 | /* Set ISP-type information. */ |
1812 | qla2x00_set_isp_flags(ha); | 1819 | qla2x00_set_isp_flags(ha); |
1820 | |||
1821 | /* Set EEH reset type to fundamental if required by hba */ | ||
1822 | if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) { | ||
1823 | pdev->needs_freset = 1; | ||
1824 | pci_save_state(pdev); | ||
1825 | } | ||
1826 | |||
1813 | /* Configure PCI I/O space */ | 1827 | /* Configure PCI I/O space */ |
1814 | ret = qla2x00_iospace_config(ha); | 1828 | ret = qla2x00_iospace_config(ha); |
1815 | if (ret) | 1829 | if (ret) |
@@ -2174,6 +2188,24 @@ qla2x00_free_device(scsi_qla_host_t *vha) | |||
2174 | { | 2188 | { |
2175 | struct qla_hw_data *ha = vha->hw; | 2189 | struct qla_hw_data *ha = vha->hw; |
2176 | 2190 | ||
2191 | qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); | ||
2192 | |||
2193 | /* Disable timer */ | ||
2194 | if (vha->timer_active) | ||
2195 | qla2x00_stop_timer(vha); | ||
2196 | |||
2197 | /* Kill the kernel thread for this host */ | ||
2198 | if (ha->dpc_thread) { | ||
2199 | struct task_struct *t = ha->dpc_thread; | ||
2200 | |||
2201 | /* | ||
2202 | * qla2xxx_wake_dpc checks for ->dpc_thread | ||
2203 | * so we need to zero it out. | ||
2204 | */ | ||
2205 | ha->dpc_thread = NULL; | ||
2206 | kthread_stop(t); | ||
2207 | } | ||
2208 | |||
2177 | qla25xx_delete_queues(vha); | 2209 | qla25xx_delete_queues(vha); |
2178 | 2210 | ||
2179 | if (ha->flags.fce_enabled) | 2211 | if (ha->flags.fce_enabled) |
@@ -2185,6 +2217,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) | |||
2185 | /* Stop currently executing firmware. */ | 2217 | /* Stop currently executing firmware. */ |
2186 | qla2x00_try_to_stop_firmware(vha); | 2218 | qla2x00_try_to_stop_firmware(vha); |
2187 | 2219 | ||
2220 | vha->flags.online = 0; | ||
2221 | |||
2188 | /* turn-off interrupts on the card */ | 2222 | /* turn-off interrupts on the card */ |
2189 | if (ha->interrupts_on) | 2223 | if (ha->interrupts_on) |
2190 | ha->isp_ops->disable_intrs(ha); | 2224 | ha->isp_ops->disable_intrs(ha); |
@@ -2859,6 +2893,13 @@ qla2x00_do_dpc(void *data) | |||
2859 | if (!base_vha->flags.init_done) | 2893 | if (!base_vha->flags.init_done) |
2860 | continue; | 2894 | continue; |
2861 | 2895 | ||
2896 | if (ha->flags.eeh_busy) { | ||
2897 | DEBUG17(qla_printk(KERN_WARNING, ha, | ||
2898 | "qla2x00_do_dpc: dpc_flags: %lx\n", | ||
2899 | base_vha->dpc_flags)); | ||
2900 | continue; | ||
2901 | } | ||
2902 | |||
2862 | DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no)); | 2903 | DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no)); |
2863 | 2904 | ||
2864 | ha->dpc_active = 1; | 2905 | ha->dpc_active = 1; |
@@ -3049,8 +3090,13 @@ qla2x00_timer(scsi_qla_host_t *vha) | |||
3049 | int index; | 3090 | int index; |
3050 | srb_t *sp; | 3091 | srb_t *sp; |
3051 | int t; | 3092 | int t; |
3093 | uint16_t w; | ||
3052 | struct qla_hw_data *ha = vha->hw; | 3094 | struct qla_hw_data *ha = vha->hw; |
3053 | struct req_que *req; | 3095 | struct req_que *req; |
3096 | |||
3097 | /* Hardware read to raise pending EEH errors during mailbox waits. */ | ||
3098 | if (!pci_channel_offline(ha->pdev)) | ||
3099 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); | ||
3054 | /* | 3100 | /* |
3055 | * Ports - Port down timer. | 3101 | * Ports - Port down timer. |
3056 | * | 3102 | * |
@@ -3252,16 +3298,23 @@ qla2x00_release_firmware(void) | |||
3252 | static pci_ers_result_t | 3298 | static pci_ers_result_t |
3253 | qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | 3299 | qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) |
3254 | { | 3300 | { |
3255 | scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); | 3301 | scsi_qla_host_t *vha = pci_get_drvdata(pdev); |
3302 | struct qla_hw_data *ha = vha->hw; | ||
3303 | |||
3304 | DEBUG2(qla_printk(KERN_WARNING, ha, "error_detected:state %x\n", | ||
3305 | state)); | ||
3256 | 3306 | ||
3257 | switch (state) { | 3307 | switch (state) { |
3258 | case pci_channel_io_normal: | 3308 | case pci_channel_io_normal: |
3309 | ha->flags.eeh_busy = 0; | ||
3259 | return PCI_ERS_RESULT_CAN_RECOVER; | 3310 | return PCI_ERS_RESULT_CAN_RECOVER; |
3260 | case pci_channel_io_frozen: | 3311 | case pci_channel_io_frozen: |
3312 | ha->flags.eeh_busy = 1; | ||
3261 | pci_disable_device(pdev); | 3313 | pci_disable_device(pdev); |
3262 | return PCI_ERS_RESULT_NEED_RESET; | 3314 | return PCI_ERS_RESULT_NEED_RESET; |
3263 | case pci_channel_io_perm_failure: | 3315 | case pci_channel_io_perm_failure: |
3264 | qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); | 3316 | ha->flags.pci_channel_io_perm_failure = 1; |
3317 | qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); | ||
3265 | return PCI_ERS_RESULT_DISCONNECT; | 3318 | return PCI_ERS_RESULT_DISCONNECT; |
3266 | } | 3319 | } |
3267 | return PCI_ERS_RESULT_NEED_RESET; | 3320 | return PCI_ERS_RESULT_NEED_RESET; |
@@ -3312,6 +3365,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3312 | struct qla_hw_data *ha = base_vha->hw; | 3365 | struct qla_hw_data *ha = base_vha->hw; |
3313 | int rc; | 3366 | int rc; |
3314 | 3367 | ||
3368 | DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n")); | ||
3369 | |||
3315 | if (ha->mem_only) | 3370 | if (ha->mem_only) |
3316 | rc = pci_enable_device_mem(pdev); | 3371 | rc = pci_enable_device_mem(pdev); |
3317 | else | 3372 | else |
@@ -3320,19 +3375,33 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3320 | if (rc) { | 3375 | if (rc) { |
3321 | qla_printk(KERN_WARNING, ha, | 3376 | qla_printk(KERN_WARNING, ha, |
3322 | "Can't re-enable PCI device after reset.\n"); | 3377 | "Can't re-enable PCI device after reset.\n"); |
3323 | |||
3324 | return ret; | 3378 | return ret; |
3325 | } | 3379 | } |
3326 | pci_set_master(pdev); | ||
3327 | 3380 | ||
3328 | if (ha->isp_ops->pci_config(base_vha)) | 3381 | if (ha->isp_ops->pci_config(base_vha)) |
3329 | return ret; | 3382 | return ret; |
3330 | 3383 | ||
3384 | #ifdef QL_DEBUG_LEVEL_17 | ||
3385 | { | ||
3386 | uint8_t b; | ||
3387 | uint32_t i; | ||
3388 | |||
3389 | printk("slot_reset_1: "); | ||
3390 | for (i = 0; i < 256; i++) { | ||
3391 | pci_read_config_byte(ha->pdev, i, &b); | ||
3392 | printk("%s%02x", (i%16) ? " " : "\n", b); | ||
3393 | } | ||
3394 | printk("\n"); | ||
3395 | } | ||
3396 | #endif | ||
3331 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 3397 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
3332 | if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) | 3398 | if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) |
3333 | ret = PCI_ERS_RESULT_RECOVERED; | 3399 | ret = PCI_ERS_RESULT_RECOVERED; |
3334 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 3400 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
3335 | 3401 | ||
3402 | DEBUG17(qla_printk(KERN_WARNING, ha, | ||
3403 | "slot_reset-return:ret=%x\n", ret)); | ||
3404 | |||
3336 | return ret; | 3405 | return ret; |
3337 | } | 3406 | } |
3338 | 3407 | ||
@@ -3343,12 +3412,17 @@ qla2xxx_pci_resume(struct pci_dev *pdev) | |||
3343 | struct qla_hw_data *ha = base_vha->hw; | 3412 | struct qla_hw_data *ha = base_vha->hw; |
3344 | int ret; | 3413 | int ret; |
3345 | 3414 | ||
3415 | DEBUG17(qla_printk(KERN_WARNING, ha, "pci_resume\n")); | ||
3416 | |||
3346 | ret = qla2x00_wait_for_hba_online(base_vha); | 3417 | ret = qla2x00_wait_for_hba_online(base_vha); |
3347 | if (ret != QLA_SUCCESS) { | 3418 | if (ret != QLA_SUCCESS) { |
3348 | qla_printk(KERN_ERR, ha, | 3419 | qla_printk(KERN_ERR, ha, |
3349 | "the device failed to resume I/O " | 3420 | "the device failed to resume I/O " |
3350 | "from slot/link_reset"); | 3421 | "from slot/link_reset"); |
3351 | } | 3422 | } |
3423 | |||
3424 | ha->flags.eeh_busy = 0; | ||
3425 | |||
3352 | pci_cleanup_aer_uncorrect_error_status(pdev); | 3426 | pci_cleanup_aer_uncorrect_error_status(pdev); |
3353 | } | 3427 | } |
3354 | 3428 | ||