diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:54:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:54:40 -0400 |
commit | c55d267de274d308927b60c3e740c1a826832317 (patch) | |
tree | 21b53a8c725d9f9650f60d94b349459d5b8dae10 /drivers/scsi/qla2xxx/qla_nx.c | |
parent | 61ef46fd45c3c62dc7c880a45dd2aa841b9af8fb (diff) | |
parent | bc898c97f7ba24def788d9f80786cf028a197122 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (170 commits)
[SCSI] scsi_dh_rdac: Add MD36xxf into device list
[SCSI] scsi_debug: add consecutive medium errors
[SCSI] libsas: fix ata list corruption issue
[SCSI] hpsa: export resettable host attribute
[SCSI] hpsa: move device attributes to avoid forward declarations
[SCSI] scsi_debug: Logical Block Provisioning (SBC3r26)
[SCSI] sd: Logical Block Provisioning update
[SCSI] Include protection operation in SCSI command trace
[SCSI] hpsa: fix incorrect PCI IDs and add two new ones (2nd try)
[SCSI] target: Fix volume size misreporting for volumes > 2TB
[SCSI] bnx2fc: Broadcom FCoE offload driver
[SCSI] fcoe: fix broken fcoe interface reset
[SCSI] fcoe: precedence bug in fcoe_filter_frames()
[SCSI] libfcoe: Remove stale fcoe-netdev entries
[SCSI] libfcoe: Move FCOE_MTU definition from fcoe.h to libfcoe.h
[SCSI] libfc: introduce __fc_fill_fc_hdr that accepts fc_hdr as an argument
[SCSI] fcoe, libfc: initialize EM anchors list and then update npiv EMs
[SCSI] Revert "[SCSI] libfc: fix exchange being deleted when the abort itself is timed out"
[SCSI] libfc: Fixing a memory leak when destroying an interface
[SCSI] megaraid_sas: Version and Changelog update
...
Fix up trivial conflicts due to whitespace differences in
drivers/scsi/libsas/{sas_ata.c,sas_scsi_host.c}
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_nx.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 191 |
1 files changed, 145 insertions, 46 deletions
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index fdb96a3584a5..76ec876e6b21 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "qla_def.h" | 7 | #include "qla_def.h" |
8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
10 | #include <scsi/scsi_tcq.h> | ||
10 | 11 | ||
11 | #define MASK(n) ((1ULL<<(n))-1) | 12 | #define MASK(n) ((1ULL<<(n))-1) |
12 | #define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \ | 13 | #define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \ |
@@ -2547,7 +2548,7 @@ qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, | |||
2547 | dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; | 2548 | dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; |
2548 | *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); | 2549 | *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); |
2549 | *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); | 2550 | *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); |
2550 | *dsd_seg++ = dsd_list_len; | 2551 | cmd_pkt->fcp_data_dseg_len = dsd_list_len; |
2551 | } else { | 2552 | } else { |
2552 | *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); | 2553 | *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); |
2553 | *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); | 2554 | *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); |
@@ -2620,6 +2621,7 @@ qla82xx_start_scsi(srb_t *sp) | |||
2620 | struct qla_hw_data *ha = vha->hw; | 2621 | struct qla_hw_data *ha = vha->hw; |
2621 | struct req_que *req = NULL; | 2622 | struct req_que *req = NULL; |
2622 | struct rsp_que *rsp = NULL; | 2623 | struct rsp_que *rsp = NULL; |
2624 | char tag[2]; | ||
2623 | 2625 | ||
2624 | /* Setup device pointers. */ | 2626 | /* Setup device pointers. */ |
2625 | ret = 0; | 2627 | ret = 0; |
@@ -2770,6 +2772,22 @@ sufficient_dsds: | |||
2770 | int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); | 2772 | int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); |
2771 | host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); | 2773 | host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); |
2772 | 2774 | ||
2775 | /* | ||
2776 | * Update tagged queuing modifier -- default is TSK_SIMPLE (0). | ||
2777 | */ | ||
2778 | if (scsi_populate_tag_msg(cmd, tag)) { | ||
2779 | switch (tag[0]) { | ||
2780 | case HEAD_OF_QUEUE_TAG: | ||
2781 | ctx->fcp_cmnd->task_attribute = | ||
2782 | TSK_HEAD_OF_QUEUE; | ||
2783 | break; | ||
2784 | case ORDERED_QUEUE_TAG: | ||
2785 | ctx->fcp_cmnd->task_attribute = | ||
2786 | TSK_ORDERED; | ||
2787 | break; | ||
2788 | } | ||
2789 | } | ||
2790 | |||
2773 | /* build FCP_CMND IU */ | 2791 | /* build FCP_CMND IU */ |
2774 | memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); | 2792 | memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); |
2775 | int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); | 2793 | int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); |
@@ -2835,6 +2853,20 @@ sufficient_dsds: | |||
2835 | host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, | 2853 | host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, |
2836 | sizeof(cmd_pkt->lun)); | 2854 | sizeof(cmd_pkt->lun)); |
2837 | 2855 | ||
2856 | /* | ||
2857 | * Update tagged queuing modifier -- default is TSK_SIMPLE (0). | ||
2858 | */ | ||
2859 | if (scsi_populate_tag_msg(cmd, tag)) { | ||
2860 | switch (tag[0]) { | ||
2861 | case HEAD_OF_QUEUE_TAG: | ||
2862 | cmd_pkt->task = TSK_HEAD_OF_QUEUE; | ||
2863 | break; | ||
2864 | case ORDERED_QUEUE_TAG: | ||
2865 | cmd_pkt->task = TSK_ORDERED; | ||
2866 | break; | ||
2867 | } | ||
2868 | } | ||
2869 | |||
2838 | /* Load SCSI command packet. */ | 2870 | /* Load SCSI command packet. */ |
2839 | memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); | 2871 | memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); |
2840 | host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); | 2872 | host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); |
@@ -3457,46 +3489,28 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha) | |||
3457 | } | 3489 | } |
3458 | } | 3490 | } |
3459 | 3491 | ||
3460 | static void | 3492 | int |
3461 | qla82xx_check_fw_alive(scsi_qla_host_t *vha) | 3493 | qla82xx_check_fw_alive(scsi_qla_host_t *vha) |
3462 | { | 3494 | { |
3463 | uint32_t fw_heartbeat_counter, halt_status; | 3495 | uint32_t fw_heartbeat_counter; |
3464 | struct qla_hw_data *ha = vha->hw; | 3496 | int status = 0; |
3465 | 3497 | ||
3466 | fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); | 3498 | fw_heartbeat_counter = qla82xx_rd_32(vha->hw, |
3499 | QLA82XX_PEG_ALIVE_COUNTER); | ||
3467 | /* all 0xff, assume AER/EEH in progress, ignore */ | 3500 | /* all 0xff, assume AER/EEH in progress, ignore */ |
3468 | if (fw_heartbeat_counter == 0xffffffff) | 3501 | if (fw_heartbeat_counter == 0xffffffff) |
3469 | return; | 3502 | return status; |
3470 | if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { | 3503 | if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { |
3471 | vha->seconds_since_last_heartbeat++; | 3504 | vha->seconds_since_last_heartbeat++; |
3472 | /* FW not alive after 2 seconds */ | 3505 | /* FW not alive after 2 seconds */ |
3473 | if (vha->seconds_since_last_heartbeat == 2) { | 3506 | if (vha->seconds_since_last_heartbeat == 2) { |
3474 | vha->seconds_since_last_heartbeat = 0; | 3507 | vha->seconds_since_last_heartbeat = 0; |
3475 | halt_status = qla82xx_rd_32(ha, | 3508 | status = 1; |
3476 | QLA82XX_PEG_HALT_STATUS1); | ||
3477 | if (halt_status & HALT_STATUS_UNRECOVERABLE) { | ||
3478 | set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); | ||
3479 | } else { | ||
3480 | qla_printk(KERN_INFO, ha, | ||
3481 | "scsi(%ld): %s - detect abort needed\n", | ||
3482 | vha->host_no, __func__); | ||
3483 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | ||
3484 | } | ||
3485 | qla2xxx_wake_dpc(vha); | ||
3486 | ha->flags.fw_hung = 1; | ||
3487 | if (ha->flags.mbox_busy) { | ||
3488 | ha->flags.mbox_int = 1; | ||
3489 | DEBUG2(qla_printk(KERN_ERR, ha, | ||
3490 | "Due to fw hung, doing premature " | ||
3491 | "completion of mbx command\n")); | ||
3492 | if (test_bit(MBX_INTR_WAIT, | ||
3493 | &ha->mbx_cmd_flags)) | ||
3494 | complete(&ha->mbx_intr_comp); | ||
3495 | } | ||
3496 | } | 3509 | } |
3497 | } else | 3510 | } else |
3498 | vha->seconds_since_last_heartbeat = 0; | 3511 | vha->seconds_since_last_heartbeat = 0; |
3499 | vha->fw_heartbeat_counter = fw_heartbeat_counter; | 3512 | vha->fw_heartbeat_counter = fw_heartbeat_counter; |
3513 | return status; | ||
3500 | } | 3514 | } |
3501 | 3515 | ||
3502 | /* | 3516 | /* |
@@ -3557,6 +3571,8 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) | |||
3557 | break; | 3571 | break; |
3558 | case QLA82XX_DEV_NEED_RESET: | 3572 | case QLA82XX_DEV_NEED_RESET: |
3559 | qla82xx_need_reset_handler(vha); | 3573 | qla82xx_need_reset_handler(vha); |
3574 | dev_init_timeout = jiffies + | ||
3575 | (ha->nx_dev_init_timeout * HZ); | ||
3560 | break; | 3576 | break; |
3561 | case QLA82XX_DEV_NEED_QUIESCENT: | 3577 | case QLA82XX_DEV_NEED_QUIESCENT: |
3562 | qla82xx_need_qsnt_handler(vha); | 3578 | qla82xx_need_qsnt_handler(vha); |
@@ -3596,30 +3612,18 @@ exit: | |||
3596 | 3612 | ||
3597 | void qla82xx_watchdog(scsi_qla_host_t *vha) | 3613 | void qla82xx_watchdog(scsi_qla_host_t *vha) |
3598 | { | 3614 | { |
3599 | uint32_t dev_state; | 3615 | uint32_t dev_state, halt_status; |
3600 | struct qla_hw_data *ha = vha->hw; | 3616 | struct qla_hw_data *ha = vha->hw; |
3601 | 3617 | ||
3602 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
3603 | |||
3604 | /* don't poll if reset is going on */ | 3618 | /* don't poll if reset is going on */ |
3605 | if (!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | 3619 | if (!ha->flags.isp82xx_reset_hdlr_active) { |
3606 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | 3620 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |
3607 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))) { | 3621 | if (dev_state == QLA82XX_DEV_NEED_RESET && |
3608 | if (dev_state == QLA82XX_DEV_NEED_RESET) { | 3622 | !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { |
3609 | qla_printk(KERN_WARNING, ha, | 3623 | qla_printk(KERN_WARNING, ha, |
3610 | "%s(): Adapter reset needed!\n", __func__); | 3624 | "%s(): Adapter reset needed!\n", __func__); |
3611 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | 3625 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); |
3612 | qla2xxx_wake_dpc(vha); | 3626 | qla2xxx_wake_dpc(vha); |
3613 | ha->flags.fw_hung = 1; | ||
3614 | if (ha->flags.mbox_busy) { | ||
3615 | ha->flags.mbox_int = 1; | ||
3616 | DEBUG2(qla_printk(KERN_ERR, ha, | ||
3617 | "Need reset, doing premature " | ||
3618 | "completion of mbx command\n")); | ||
3619 | if (test_bit(MBX_INTR_WAIT, | ||
3620 | &ha->mbx_cmd_flags)) | ||
3621 | complete(&ha->mbx_intr_comp); | ||
3622 | } | ||
3623 | } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && | 3627 | } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && |
3624 | !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) { | 3628 | !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) { |
3625 | DEBUG(qla_printk(KERN_INFO, ha, | 3629 | DEBUG(qla_printk(KERN_INFO, ha, |
@@ -3629,6 +3633,31 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) | |||
3629 | qla2xxx_wake_dpc(vha); | 3633 | qla2xxx_wake_dpc(vha); |
3630 | } else { | 3634 | } else { |
3631 | qla82xx_check_fw_alive(vha); | 3635 | qla82xx_check_fw_alive(vha); |
3636 | if (qla82xx_check_fw_alive(vha)) { | ||
3637 | halt_status = qla82xx_rd_32(ha, | ||
3638 | QLA82XX_PEG_HALT_STATUS1); | ||
3639 | if (halt_status & HALT_STATUS_UNRECOVERABLE) { | ||
3640 | set_bit(ISP_UNRECOVERABLE, | ||
3641 | &vha->dpc_flags); | ||
3642 | } else { | ||
3643 | qla_printk(KERN_INFO, ha, | ||
3644 | "scsi(%ld): %s - detect abort needed\n", | ||
3645 | vha->host_no, __func__); | ||
3646 | set_bit(ISP_ABORT_NEEDED, | ||
3647 | &vha->dpc_flags); | ||
3648 | } | ||
3649 | qla2xxx_wake_dpc(vha); | ||
3650 | ha->flags.isp82xx_fw_hung = 1; | ||
3651 | if (ha->flags.mbox_busy) { | ||
3652 | ha->flags.mbox_int = 1; | ||
3653 | DEBUG2(qla_printk(KERN_ERR, ha, | ||
3654 | "Due to fw hung, doing premature " | ||
3655 | "completion of mbx command\n")); | ||
3656 | if (test_bit(MBX_INTR_WAIT, | ||
3657 | &ha->mbx_cmd_flags)) | ||
3658 | complete(&ha->mbx_intr_comp); | ||
3659 | } | ||
3660 | } | ||
3632 | } | 3661 | } |
3633 | } | 3662 | } |
3634 | } | 3663 | } |
@@ -3663,6 +3692,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) | |||
3663 | "Exiting.\n", __func__, vha->host_no); | 3692 | "Exiting.\n", __func__, vha->host_no); |
3664 | return QLA_SUCCESS; | 3693 | return QLA_SUCCESS; |
3665 | } | 3694 | } |
3695 | ha->flags.isp82xx_reset_hdlr_active = 1; | ||
3666 | 3696 | ||
3667 | qla82xx_idc_lock(ha); | 3697 | qla82xx_idc_lock(ha); |
3668 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 3698 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |
@@ -3683,7 +3713,8 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) | |||
3683 | qla82xx_idc_unlock(ha); | 3713 | qla82xx_idc_unlock(ha); |
3684 | 3714 | ||
3685 | if (rval == QLA_SUCCESS) { | 3715 | if (rval == QLA_SUCCESS) { |
3686 | ha->flags.fw_hung = 0; | 3716 | ha->flags.isp82xx_fw_hung = 0; |
3717 | ha->flags.isp82xx_reset_hdlr_active = 0; | ||
3687 | qla82xx_restart_isp(vha); | 3718 | qla82xx_restart_isp(vha); |
3688 | } | 3719 | } |
3689 | 3720 | ||
@@ -3791,3 +3822,71 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha) | |||
3791 | 3822 | ||
3792 | return status; | 3823 | return status; |
3793 | } | 3824 | } |
3825 | |||
3826 | void | ||
3827 | qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) | ||
3828 | { | ||
3829 | int i; | ||
3830 | unsigned long flags; | ||
3831 | struct qla_hw_data *ha = vha->hw; | ||
3832 | |||
3833 | /* Check if 82XX firmware is alive or not | ||
3834 | * We may have arrived here from NEED_RESET | ||
3835 | * detection only | ||
3836 | */ | ||
3837 | if (!ha->flags.isp82xx_fw_hung) { | ||
3838 | for (i = 0; i < 2; i++) { | ||
3839 | msleep(1000); | ||
3840 | if (qla82xx_check_fw_alive(vha)) { | ||
3841 | ha->flags.isp82xx_fw_hung = 1; | ||
3842 | if (ha->flags.mbox_busy) { | ||
3843 | ha->flags.mbox_int = 1; | ||
3844 | complete(&ha->mbx_intr_comp); | ||
3845 | } | ||
3846 | break; | ||
3847 | } | ||
3848 | } | ||
3849 | } | ||
3850 | |||
3851 | /* Abort all commands gracefully if fw NOT hung */ | ||
3852 | if (!ha->flags.isp82xx_fw_hung) { | ||
3853 | int cnt, que; | ||
3854 | srb_t *sp; | ||
3855 | struct req_que *req; | ||
3856 | |||
3857 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
3858 | for (que = 0; que < ha->max_req_queues; que++) { | ||
3859 | req = ha->req_q_map[que]; | ||
3860 | if (!req) | ||
3861 | continue; | ||
3862 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { | ||
3863 | sp = req->outstanding_cmds[cnt]; | ||
3864 | if (sp) { | ||
3865 | if (!sp->ctx || | ||
3866 | (sp->flags & SRB_FCP_CMND_DMA_VALID)) { | ||
3867 | spin_unlock_irqrestore( | ||
3868 | &ha->hardware_lock, flags); | ||
3869 | if (ha->isp_ops->abort_command(sp)) { | ||
3870 | qla_printk(KERN_INFO, ha, | ||
3871 | "scsi(%ld): mbx abort command failed in %s\n", | ||
3872 | vha->host_no, __func__); | ||
3873 | } else { | ||
3874 | qla_printk(KERN_INFO, ha, | ||
3875 | "scsi(%ld): mbx abort command success in %s\n", | ||
3876 | vha->host_no, __func__); | ||
3877 | } | ||
3878 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
3879 | } | ||
3880 | } | ||
3881 | } | ||
3882 | } | ||
3883 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
3884 | |||
3885 | /* Wait for pending cmds (physical and virtual) to complete */ | ||
3886 | if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, | ||
3887 | WAIT_HOST) == QLA_SUCCESS) { | ||
3888 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
3889 | "Done wait for pending commands\n")); | ||
3890 | } | ||
3891 | } | ||
3892 | } | ||