diff options
author | David C Somayajulu <david.somayajulu@qlogic.com> | 2007-01-22 15:26:11 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-01-27 10:15:46 -0500 |
commit | 477ffb9d8732f30e7ab2d20f6ed0c22bad37a4a5 (patch) | |
tree | d8633736db9eb4609d935bc5ff0c1a8fba5d07f4 /drivers/scsi/qla4xxx/ql4_os.c | |
parent | 938e2ac0b7ac72d264783b0b548eb6078c295294 (diff) |
[SCSI] qla4xxx: bug fixes
The included patch fixes the following issues:
1. qla3xxx/qla4xxx co-existence issue which can result in a lockup
when qla3xxx driver is unloaded, or when ifdown; ifup is performed on
one of the interfaces correponding to qla3xxx. This is because qla4xxx
HBA supports one ethernet and iscsi interfaces per port. Both iscsi
and ethernet interfaces share the same state machine. The problem has
to do with synchronizing access to the state machine in the event of a
reset
2. mutex_lock() is sometimes not followed by mutex_unlock() prior to
invoking a msleep() in qla4xxx_mailbox_command()
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9ef693c8809..81fb7bd44f0 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -40,6 +40,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging, | |||
40 | "Option to enable extended error logging, " | 40 | "Option to enable extended error logging, " |
41 | "Default is 0 - no logging, 1 - debug logging"); | 41 | "Default is 0 - no logging, 1 - debug logging"); |
42 | 42 | ||
43 | int ql4_mod_unload = 0; | ||
44 | |||
43 | /* | 45 | /* |
44 | * SCSI host template entry points | 46 | * SCSI host template entry points |
45 | */ | 47 | */ |
@@ -422,6 +424,9 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, | |||
422 | goto qc_host_busy; | 424 | goto qc_host_busy; |
423 | } | 425 | } |
424 | 426 | ||
427 | if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) | ||
428 | goto qc_host_busy; | ||
429 | |||
425 | spin_unlock_irq(ha->host->host_lock); | 430 | spin_unlock_irq(ha->host->host_lock); |
426 | 431 | ||
427 | srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); | 432 | srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); |
@@ -707,16 +712,12 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) | |||
707 | return stat; | 712 | return stat; |
708 | } | 713 | } |
709 | 714 | ||
710 | /** | 715 | static void qla4xxx_hw_reset(struct scsi_qla_host *ha) |
711 | * qla4xxx_soft_reset - performs soft reset. | ||
712 | * @ha: Pointer to host adapter structure. | ||
713 | **/ | ||
714 | int qla4xxx_soft_reset(struct scsi_qla_host *ha) | ||
715 | { | 716 | { |
716 | uint32_t max_wait_time; | ||
717 | unsigned long flags = 0; | ||
718 | int status = QLA_ERROR; | ||
719 | uint32_t ctrl_status; | 717 | uint32_t ctrl_status; |
718 | unsigned long flags = 0; | ||
719 | |||
720 | DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); | ||
720 | 721 | ||
721 | spin_lock_irqsave(&ha->hardware_lock, flags); | 722 | spin_lock_irqsave(&ha->hardware_lock, flags); |
722 | 723 | ||
@@ -733,6 +734,20 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha) | |||
733 | readl(&ha->reg->ctrl_status); | 734 | readl(&ha->reg->ctrl_status); |
734 | 735 | ||
735 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 736 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
737 | } | ||
738 | |||
739 | /** | ||
740 | * qla4xxx_soft_reset - performs soft reset. | ||
741 | * @ha: Pointer to host adapter structure. | ||
742 | **/ | ||
743 | int qla4xxx_soft_reset(struct scsi_qla_host *ha) | ||
744 | { | ||
745 | uint32_t max_wait_time; | ||
746 | unsigned long flags = 0; | ||
747 | int status = QLA_ERROR; | ||
748 | uint32_t ctrl_status; | ||
749 | |||
750 | qla4xxx_hw_reset(ha); | ||
736 | 751 | ||
737 | /* Wait until the Network Reset Intr bit is cleared */ | 752 | /* Wait until the Network Reset Intr bit is cleared */ |
738 | max_wait_time = RESET_INTR_TOV; | 753 | max_wait_time = RESET_INTR_TOV; |
@@ -966,10 +981,12 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
966 | struct scsi_qla_host *ha = | 981 | struct scsi_qla_host *ha = |
967 | container_of(work, struct scsi_qla_host, dpc_work); | 982 | container_of(work, struct scsi_qla_host, dpc_work); |
968 | struct ddb_entry *ddb_entry, *dtemp; | 983 | struct ddb_entry *ddb_entry, *dtemp; |
984 | int status = QLA_ERROR; | ||
969 | 985 | ||
970 | DEBUG2(printk("scsi%ld: %s: DPC handler waking up." | 986 | DEBUG2(printk("scsi%ld: %s: DPC handler waking up." |
971 | "flags = 0x%08lx, dpc_flags = 0x%08lx\n", | 987 | "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n", |
972 | ha->host_no, __func__, ha->flags, ha->dpc_flags)); | 988 | ha->host_no, __func__, ha->flags, ha->dpc_flags, |
989 | readw(&ha->reg->ctrl_status))); | ||
973 | 990 | ||
974 | /* Initialization not yet finished. Don't do anything yet. */ | 991 | /* Initialization not yet finished. Don't do anything yet. */ |
975 | if (!test_bit(AF_INIT_DONE, &ha->flags)) | 992 | if (!test_bit(AF_INIT_DONE, &ha->flags)) |
@@ -983,31 +1000,28 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
983 | test_bit(DPC_RESET_HA, &ha->dpc_flags)) | 1000 | test_bit(DPC_RESET_HA, &ha->dpc_flags)) |
984 | qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); | 1001 | qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); |
985 | 1002 | ||
986 | if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { | 1003 | if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { |
987 | uint8_t wait_time = RESET_INTR_TOV; | 1004 | uint8_t wait_time = RESET_INTR_TOV; |
988 | unsigned long flags = 0; | ||
989 | |||
990 | qla4xxx_flush_active_srbs(ha); | ||
991 | 1005 | ||
992 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
993 | while ((readw(&ha->reg->ctrl_status) & | 1006 | while ((readw(&ha->reg->ctrl_status) & |
994 | (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { | 1007 | (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { |
995 | if (--wait_time == 0) | 1008 | if (--wait_time == 0) |
996 | break; | 1009 | break; |
997 | |||
998 | spin_unlock_irqrestore(&ha->hardware_lock, | ||
999 | flags); | ||
1000 | |||
1001 | msleep(1000); | 1010 | msleep(1000); |
1002 | |||
1003 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1004 | } | 1011 | } |
1005 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1006 | |||
1007 | if (wait_time == 0) | 1012 | if (wait_time == 0) |
1008 | DEBUG2(printk("scsi%ld: %s: SR|FSR " | 1013 | DEBUG2(printk("scsi%ld: %s: SR|FSR " |
1009 | "bit not cleared-- resetting\n", | 1014 | "bit not cleared-- resetting\n", |
1010 | ha->host_no, __func__)); | 1015 | ha->host_no, __func__)); |
1016 | qla4xxx_flush_active_srbs(ha); | ||
1017 | if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { | ||
1018 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | ||
1019 | status = qla4xxx_initialize_adapter(ha, | ||
1020 | PRESERVE_DDB_LIST); | ||
1021 | } | ||
1022 | clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); | ||
1023 | if (status == QLA_SUCCESS) | ||
1024 | qla4xxx_enable_intrs(ha); | ||
1011 | } | 1025 | } |
1012 | } | 1026 | } |
1013 | 1027 | ||
@@ -1062,7 +1076,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) | |||
1062 | 1076 | ||
1063 | /* Issue Soft Reset to put firmware in unknown state */ | 1077 | /* Issue Soft Reset to put firmware in unknown state */ |
1064 | if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) | 1078 | if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) |
1065 | qla4xxx_soft_reset(ha); | 1079 | qla4xxx_hw_reset(ha); |
1066 | 1080 | ||
1067 | /* Remove timer thread, if present */ | 1081 | /* Remove timer thread, if present */ |
1068 | if (ha->timer_active) | 1082 | if (ha->timer_active) |
@@ -1198,7 +1212,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
1198 | INIT_LIST_HEAD(&ha->free_srb_q); | 1212 | INIT_LIST_HEAD(&ha->free_srb_q); |
1199 | 1213 | ||
1200 | mutex_init(&ha->mbox_sem); | 1214 | mutex_init(&ha->mbox_sem); |
1201 | init_waitqueue_head(&ha->mailbox_wait_queue); | ||
1202 | 1215 | ||
1203 | spin_lock_init(&ha->hardware_lock); | 1216 | spin_lock_init(&ha->hardware_lock); |
1204 | 1217 | ||
@@ -1665,6 +1678,7 @@ no_srp_cache: | |||
1665 | 1678 | ||
1666 | static void __exit qla4xxx_module_exit(void) | 1679 | static void __exit qla4xxx_module_exit(void) |
1667 | { | 1680 | { |
1681 | ql4_mod_unload = 1; | ||
1668 | pci_unregister_driver(&qla4xxx_pci_driver); | 1682 | pci_unregister_driver(&qla4xxx_pci_driver); |
1669 | iscsi_unregister_transport(&qla4xxx_iscsi_transport); | 1683 | iscsi_unregister_transport(&qla4xxx_iscsi_transport); |
1670 | kmem_cache_destroy(srb_cachep); | 1684 | kmem_cache_destroy(srb_cachep); |