diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 116 |
1 files changed, 61 insertions, 55 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 370d40ff1529..0d48fb4d1044 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -79,8 +79,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); | |||
79 | /* | 79 | /* |
80 | * SCSI host template entry points | 80 | * SCSI host template entry points |
81 | */ | 81 | */ |
82 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, | 82 | static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); |
83 | void (*done) (struct scsi_cmnd *)); | ||
84 | static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); | 83 | static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); |
85 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); | 84 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); |
86 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); | 85 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); |
@@ -167,8 +166,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) | |||
167 | "of (%d) secs exhausted, marking device DEAD.\n", | 166 | "of (%d) secs exhausted, marking device DEAD.\n", |
168 | ha->host_no, __func__, ddb_entry->fw_ddb_index, | 167 | ha->host_no, __func__, ddb_entry->fw_ddb_index, |
169 | QL4_SESS_RECOVERY_TMO)); | 168 | QL4_SESS_RECOVERY_TMO)); |
170 | |||
171 | qla4xxx_wake_dpc(ha); | ||
172 | } | 169 | } |
173 | } | 170 | } |
174 | 171 | ||
@@ -466,7 +463,7 @@ void qla4xxx_srb_compl(struct kref *ref) | |||
466 | * completion handling). Unfortunely, it sometimes calls the scheduler | 463 | * completion handling). Unfortunely, it sometimes calls the scheduler |
467 | * in interrupt context which is a big NO! NO!. | 464 | * in interrupt context which is a big NO! NO!. |
468 | **/ | 465 | **/ |
469 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, | 466 | static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd, |
470 | void (*done)(struct scsi_cmnd *)) | 467 | void (*done)(struct scsi_cmnd *)) |
471 | { | 468 | { |
472 | struct scsi_qla_host *ha = to_qla_host(cmd->device->host); | 469 | struct scsi_qla_host *ha = to_qla_host(cmd->device->host); |
@@ -540,6 +537,8 @@ qc_fail_command: | |||
540 | return 0; | 537 | return 0; |
541 | } | 538 | } |
542 | 539 | ||
540 | static DEF_SCSI_QCMD(qla4xxx_queuecommand) | ||
541 | |||
543 | /** | 542 | /** |
544 | * qla4xxx_mem_free - frees memory allocated to adapter | 543 | * qla4xxx_mem_free - frees memory allocated to adapter |
545 | * @ha: Pointer to host adapter structure. | 544 | * @ha: Pointer to host adapter structure. |
@@ -573,10 +572,6 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
573 | if (ha->nx_pcibase) | 572 | if (ha->nx_pcibase) |
574 | iounmap( | 573 | iounmap( |
575 | (struct device_reg_82xx __iomem *)ha->nx_pcibase); | 574 | (struct device_reg_82xx __iomem *)ha->nx_pcibase); |
576 | |||
577 | if (ha->nx_db_wr_ptr) | ||
578 | iounmap( | ||
579 | (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr); | ||
580 | } else if (ha->reg) | 575 | } else if (ha->reg) |
581 | iounmap(ha->reg); | 576 | iounmap(ha->reg); |
582 | pci_release_regions(ha->pdev); | 577 | pci_release_regions(ha->pdev); |
@@ -692,7 +687,9 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) | |||
692 | qla4xxx_wake_dpc(ha); | 687 | qla4xxx_wake_dpc(ha); |
693 | qla4xxx_mailbox_premature_completion(ha); | 688 | qla4xxx_mailbox_premature_completion(ha); |
694 | } | 689 | } |
695 | } | 690 | } else |
691 | ha->seconds_since_last_heartbeat = 0; | ||
692 | |||
696 | ha->fw_heartbeat_counter = fw_heartbeat_counter; | 693 | ha->fw_heartbeat_counter = fw_heartbeat_counter; |
697 | } | 694 | } |
698 | 695 | ||
@@ -885,7 +882,13 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) | |||
885 | /* Find a command that hasn't completed. */ | 882 | /* Find a command that hasn't completed. */ |
886 | for (index = 0; index < ha->host->can_queue; index++) { | 883 | for (index = 0; index < ha->host->can_queue; index++) { |
887 | cmd = scsi_host_find_tag(ha->host, index); | 884 | cmd = scsi_host_find_tag(ha->host, index); |
888 | if (cmd != NULL) | 885 | /* |
886 | * We cannot just check if the index is valid, | ||
887 | * becase if we are run from the scsi eh, then | ||
888 | * the scsi/block layer is going to prevent | ||
889 | * the tag from being released. | ||
890 | */ | ||
891 | if (cmd != NULL && CMD_SP(cmd)) | ||
889 | break; | 892 | break; |
890 | } | 893 | } |
891 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 894 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
@@ -937,11 +940,14 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha) | |||
937 | { | 940 | { |
938 | uint32_t max_wait_time; | 941 | uint32_t max_wait_time; |
939 | unsigned long flags = 0; | 942 | unsigned long flags = 0; |
940 | int status = QLA_ERROR; | 943 | int status; |
941 | uint32_t ctrl_status; | 944 | uint32_t ctrl_status; |
942 | 945 | ||
943 | qla4xxx_hw_reset(ha); | 946 | status = qla4xxx_hw_reset(ha); |
947 | if (status != QLA_SUCCESS) | ||
948 | return status; | ||
944 | 949 | ||
950 | status = QLA_ERROR; | ||
945 | /* Wait until the Network Reset Intr bit is cleared */ | 951 | /* Wait until the Network Reset Intr bit is cleared */ |
946 | max_wait_time = RESET_INTR_TOV; | 952 | max_wait_time = RESET_INTR_TOV; |
947 | do { | 953 | do { |
@@ -1101,7 +1107,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) | |||
1101 | ha->host_no, __func__)); | 1107 | ha->host_no, __func__)); |
1102 | status = ha->isp_ops->reset_firmware(ha); | 1108 | status = ha->isp_ops->reset_firmware(ha); |
1103 | if (status == QLA_SUCCESS) { | 1109 | if (status == QLA_SUCCESS) { |
1104 | qla4xxx_cmd_wait(ha); | 1110 | if (!test_bit(AF_FW_RECOVERY, &ha->flags)) |
1111 | qla4xxx_cmd_wait(ha); | ||
1105 | ha->isp_ops->disable_intrs(ha); | 1112 | ha->isp_ops->disable_intrs(ha); |
1106 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | 1113 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); |
1107 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); | 1114 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); |
@@ -1118,7 +1125,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) | |||
1118 | * or if stop_firmware fails for ISP-82xx. | 1125 | * or if stop_firmware fails for ISP-82xx. |
1119 | * This is the default case for ISP-4xxx */ | 1126 | * This is the default case for ISP-4xxx */ |
1120 | if (!is_qla8022(ha) || reset_chip) { | 1127 | if (!is_qla8022(ha) || reset_chip) { |
1121 | qla4xxx_cmd_wait(ha); | 1128 | if (!test_bit(AF_FW_RECOVERY, &ha->flags)) |
1129 | qla4xxx_cmd_wait(ha); | ||
1122 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | 1130 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); |
1123 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); | 1131 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); |
1124 | DEBUG2(ql4_printk(KERN_INFO, ha, | 1132 | DEBUG2(ql4_printk(KERN_INFO, ha, |
@@ -1471,24 +1479,10 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) | |||
1471 | db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ | 1479 | db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ |
1472 | db_len = pci_resource_len(pdev, 4); | 1480 | db_len = pci_resource_len(pdev, 4); |
1473 | 1481 | ||
1474 | /* mapping of doorbell write pointer */ | 1482 | ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : |
1475 | ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base + | 1483 | QLA82XX_CAM_RAM_DB2); |
1476 | (ha->pdev->devfn << 12), 4); | ||
1477 | if (!ha->nx_db_wr_ptr) { | ||
1478 | printk(KERN_ERR | ||
1479 | "cannot remap MMIO doorbell-write (%s), aborting\n", | ||
1480 | pci_name(pdev)); | ||
1481 | goto iospace_error_exit; | ||
1482 | } | ||
1483 | /* mapping of doorbell read pointer */ | ||
1484 | ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) + | ||
1485 | (ha->pdev->devfn * 8); | ||
1486 | if (!ha->nx_db_rd_ptr) | ||
1487 | printk(KERN_ERR | ||
1488 | "cannot remap MMIO doorbell-read (%s), aborting\n", | ||
1489 | pci_name(pdev)); | ||
1490 | return 0; | ||
1491 | 1484 | ||
1485 | return 0; | ||
1492 | iospace_error_exit: | 1486 | iospace_error_exit: |
1493 | return -ENOMEM; | 1487 | return -ENOMEM; |
1494 | } | 1488 | } |
@@ -1960,13 +1954,11 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) | |||
1960 | { | 1954 | { |
1961 | unsigned long wait_online; | 1955 | unsigned long wait_online; |
1962 | 1956 | ||
1963 | wait_online = jiffies + (30 * HZ); | 1957 | wait_online = jiffies + (HBA_ONLINE_TOV * HZ); |
1964 | while (time_before(jiffies, wait_online)) { | 1958 | while (time_before(jiffies, wait_online)) { |
1965 | 1959 | ||
1966 | if (adapter_up(ha)) | 1960 | if (adapter_up(ha)) |
1967 | return QLA_SUCCESS; | 1961 | return QLA_SUCCESS; |
1968 | else if (ha->retry_reset_ha_cnt == 0) | ||
1969 | return QLA_ERROR; | ||
1970 | 1962 | ||
1971 | msleep(2000); | 1963 | msleep(2000); |
1972 | } | 1964 | } |
@@ -2021,6 +2013,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) | |||
2021 | unsigned int id = cmd->device->id; | 2013 | unsigned int id = cmd->device->id; |
2022 | unsigned int lun = cmd->device->lun; | 2014 | unsigned int lun = cmd->device->lun; |
2023 | unsigned long serial = cmd->serial_number; | 2015 | unsigned long serial = cmd->serial_number; |
2016 | unsigned long flags; | ||
2024 | struct srb *srb = NULL; | 2017 | struct srb *srb = NULL; |
2025 | int ret = SUCCESS; | 2018 | int ret = SUCCESS; |
2026 | int wait = 0; | 2019 | int wait = 0; |
@@ -2029,12 +2022,14 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) | |||
2029 | "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", | 2022 | "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", |
2030 | ha->host_no, id, lun, cmd, serial); | 2023 | ha->host_no, id, lun, cmd, serial); |
2031 | 2024 | ||
2025 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2032 | srb = (struct srb *) CMD_SP(cmd); | 2026 | srb = (struct srb *) CMD_SP(cmd); |
2033 | 2027 | if (!srb) { | |
2034 | if (!srb) | 2028 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
2035 | return SUCCESS; | 2029 | return SUCCESS; |
2036 | 2030 | } | |
2037 | kref_get(&srb->srb_ref); | 2031 | kref_get(&srb->srb_ref); |
2032 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2038 | 2033 | ||
2039 | if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { | 2034 | if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { |
2040 | DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", | 2035 | DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", |
@@ -2267,6 +2262,8 @@ qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | |||
2267 | qla4xxx_mailbox_premature_completion(ha); | 2262 | qla4xxx_mailbox_premature_completion(ha); |
2268 | qla4xxx_free_irqs(ha); | 2263 | qla4xxx_free_irqs(ha); |
2269 | pci_disable_device(pdev); | 2264 | pci_disable_device(pdev); |
2265 | /* Return back all IOs */ | ||
2266 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); | ||
2270 | return PCI_ERS_RESULT_NEED_RESET; | 2267 | return PCI_ERS_RESULT_NEED_RESET; |
2271 | case pci_channel_io_perm_failure: | 2268 | case pci_channel_io_perm_failure: |
2272 | set_bit(AF_EEH_BUSY, &ha->flags); | 2269 | set_bit(AF_EEH_BUSY, &ha->flags); |
@@ -2290,17 +2287,13 @@ qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) | |||
2290 | if (!is_aer_supported(ha)) | 2287 | if (!is_aer_supported(ha)) |
2291 | return PCI_ERS_RESULT_NONE; | 2288 | return PCI_ERS_RESULT_NONE; |
2292 | 2289 | ||
2293 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { | 2290 | return PCI_ERS_RESULT_RECOVERED; |
2294 | ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: firmware hang -- " | ||
2295 | "mmio_enabled\n", ha->host_no, __func__); | ||
2296 | return PCI_ERS_RESULT_NEED_RESET; | ||
2297 | } else | ||
2298 | return PCI_ERS_RESULT_RECOVERED; | ||
2299 | } | 2291 | } |
2300 | 2292 | ||
2301 | uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) | 2293 | static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) |
2302 | { | 2294 | { |
2303 | uint32_t rval = QLA_ERROR; | 2295 | uint32_t rval = QLA_ERROR; |
2296 | uint32_t ret = 0; | ||
2304 | int fn; | 2297 | int fn; |
2305 | struct pci_dev *other_pdev = NULL; | 2298 | struct pci_dev *other_pdev = NULL; |
2306 | 2299 | ||
@@ -2312,7 +2305,6 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) | |||
2312 | clear_bit(AF_ONLINE, &ha->flags); | 2305 | clear_bit(AF_ONLINE, &ha->flags); |
2313 | qla4xxx_mark_all_devices_missing(ha); | 2306 | qla4xxx_mark_all_devices_missing(ha); |
2314 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | 2307 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); |
2315 | qla4xxx_abort_active_cmds(ha, DID_RESET << 16); | ||
2316 | } | 2308 | } |
2317 | 2309 | ||
2318 | fn = PCI_FUNC(ha->pdev->devfn); | 2310 | fn = PCI_FUNC(ha->pdev->devfn); |
@@ -2375,7 +2367,16 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) | |||
2375 | /* Clear driver state register */ | 2367 | /* Clear driver state register */ |
2376 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); | 2368 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); |
2377 | qla4_8xxx_set_drv_active(ha); | 2369 | qla4_8xxx_set_drv_active(ha); |
2378 | ha->isp_ops->enable_intrs(ha); | 2370 | ret = qla4xxx_request_irqs(ha); |
2371 | if (ret) { | ||
2372 | ql4_printk(KERN_WARNING, ha, "Failed to " | ||
2373 | "reserve interrupt %d already in use.\n", | ||
2374 | ha->pdev->irq); | ||
2375 | rval = QLA_ERROR; | ||
2376 | } else { | ||
2377 | ha->isp_ops->enable_intrs(ha); | ||
2378 | rval = QLA_SUCCESS; | ||
2379 | } | ||
2379 | } | 2380 | } |
2380 | qla4_8xxx_idc_unlock(ha); | 2381 | qla4_8xxx_idc_unlock(ha); |
2381 | } else { | 2382 | } else { |
@@ -2387,8 +2388,18 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) | |||
2387 | clear_bit(AF_FW_RECOVERY, &ha->flags); | 2388 | clear_bit(AF_FW_RECOVERY, &ha->flags); |
2388 | rval = qla4xxx_initialize_adapter(ha, | 2389 | rval = qla4xxx_initialize_adapter(ha, |
2389 | PRESERVE_DDB_LIST); | 2390 | PRESERVE_DDB_LIST); |
2390 | if (rval == QLA_SUCCESS) | 2391 | if (rval == QLA_SUCCESS) { |
2391 | ha->isp_ops->enable_intrs(ha); | 2392 | ret = qla4xxx_request_irqs(ha); |
2393 | if (ret) { | ||
2394 | ql4_printk(KERN_WARNING, ha, "Failed to" | ||
2395 | " reserve interrupt %d already in" | ||
2396 | " use.\n", ha->pdev->irq); | ||
2397 | rval = QLA_ERROR; | ||
2398 | } else { | ||
2399 | ha->isp_ops->enable_intrs(ha); | ||
2400 | rval = QLA_SUCCESS; | ||
2401 | } | ||
2402 | } | ||
2392 | qla4_8xxx_idc_lock(ha); | 2403 | qla4_8xxx_idc_lock(ha); |
2393 | qla4_8xxx_set_drv_active(ha); | 2404 | qla4_8xxx_set_drv_active(ha); |
2394 | qla4_8xxx_idc_unlock(ha); | 2405 | qla4_8xxx_idc_unlock(ha); |
@@ -2430,12 +2441,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev) | |||
2430 | goto exit_slot_reset; | 2441 | goto exit_slot_reset; |
2431 | } | 2442 | } |
2432 | 2443 | ||
2433 | ret = qla4xxx_request_irqs(ha); | 2444 | ha->isp_ops->disable_intrs(ha); |
2434 | if (ret) { | ||
2435 | ql4_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d" | ||
2436 | " already in use.\n", pdev->irq); | ||
2437 | goto exit_slot_reset; | ||
2438 | } | ||
2439 | 2445 | ||
2440 | if (is_qla8022(ha)) { | 2446 | if (is_qla8022(ha)) { |
2441 | if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { | 2447 | if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { |