diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 146 |
1 files changed, 95 insertions, 51 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 967836ef5ab..a4acb0dd7be 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -29,10 +29,6 @@ static struct kmem_cache *srb_cachep; | |||
29 | /* | 29 | /* |
30 | * Module parameter information and variables | 30 | * Module parameter information and variables |
31 | */ | 31 | */ |
32 | int ql4xdiscoverywait = 60; | ||
33 | module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR); | ||
34 | MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time"); | ||
35 | |||
36 | int ql4xdontresethba = 0; | 32 | int ql4xdontresethba = 0; |
37 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); | 33 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); |
38 | MODULE_PARM_DESC(ql4xdontresethba, | 34 | MODULE_PARM_DESC(ql4xdontresethba, |
@@ -55,6 +51,17 @@ MODULE_PARM_DESC(ql4xenablemsix, | |||
55 | " 2 = enable MSI interrupt mechanism."); | 51 | " 2 = enable MSI interrupt mechanism."); |
56 | 52 | ||
57 | #define QL4_DEF_QDEPTH 32 | 53 | #define QL4_DEF_QDEPTH 32 |
54 | static int ql4xmaxqdepth = QL4_DEF_QDEPTH; | ||
55 | module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); | ||
56 | MODULE_PARM_DESC(ql4xmaxqdepth, | ||
57 | "Maximum queue depth to report for target devices.\n" | ||
58 | " Default: 32."); | ||
59 | |||
60 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; | ||
61 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); | ||
62 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, | ||
63 | "Target Session Recovery Timeout.\n" | ||
64 | " Default: 30 sec."); | ||
58 | 65 | ||
59 | /* | 66 | /* |
60 | * SCSI host template entry points | 67 | * SCSI host template entry points |
@@ -165,7 +172,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) | |||
165 | DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " | 172 | DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " |
166 | "of (%d) secs exhausted, marking device DEAD.\n", | 173 | "of (%d) secs exhausted, marking device DEAD.\n", |
167 | ha->host_no, __func__, ddb_entry->fw_ddb_index, | 174 | ha->host_no, __func__, ddb_entry->fw_ddb_index, |
168 | QL4_SESS_RECOVERY_TMO)); | 175 | ddb_entry->sess->recovery_tmo)); |
169 | } | 176 | } |
170 | } | 177 | } |
171 | 178 | ||
@@ -295,7 +302,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) | |||
295 | { | 302 | { |
296 | int err; | 303 | int err; |
297 | 304 | ||
298 | ddb_entry->sess->recovery_tmo = QL4_SESS_RECOVERY_TMO; | 305 | ddb_entry->sess->recovery_tmo = ql4xsess_recovery_tmo; |
299 | 306 | ||
300 | err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); | 307 | err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); |
301 | if (err) { | 308 | if (err) { |
@@ -753,12 +760,6 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) | |||
753 | if (!pci_channel_offline(ha->pdev)) | 760 | if (!pci_channel_offline(ha->pdev)) |
754 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); | 761 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); |
755 | 762 | ||
756 | if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { | ||
757 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n", | ||
758 | __func__)); | ||
759 | return; | ||
760 | } | ||
761 | |||
762 | if (is_qla8022(ha)) { | 763 | if (is_qla8022(ha)) { |
763 | qla4_8xxx_watchdog(ha); | 764 | qla4_8xxx_watchdog(ha); |
764 | } | 765 | } |
@@ -1067,7 +1068,6 @@ void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) | |||
1067 | 1068 | ||
1068 | /* Disable the board */ | 1069 | /* Disable the board */ |
1069 | ql4_printk(KERN_INFO, ha, "Disabling the board\n"); | 1070 | ql4_printk(KERN_INFO, ha, "Disabling the board\n"); |
1070 | set_bit(AF_HBA_GOING_AWAY, &ha->flags); | ||
1071 | 1071 | ||
1072 | qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); | 1072 | qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); |
1073 | qla4xxx_mark_all_devices_missing(ha); | 1073 | qla4xxx_mark_all_devices_missing(ha); |
@@ -1218,6 +1218,27 @@ recover_ha_init_adapter: | |||
1218 | return status; | 1218 | return status; |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) | ||
1222 | { | ||
1223 | struct ddb_entry *ddb_entry, *dtemp; | ||
1224 | |||
1225 | list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { | ||
1226 | if ((atomic_read(&ddb_entry->state) == DDB_STATE_MISSING) || | ||
1227 | (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD)) { | ||
1228 | if (ddb_entry->fw_ddb_device_state == | ||
1229 | DDB_DS_SESSION_ACTIVE) { | ||
1230 | atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); | ||
1231 | ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" | ||
1232 | " marked ONLINE\n", ha->host_no, __func__, | ||
1233 | ddb_entry->fw_ddb_index); | ||
1234 | |||
1235 | iscsi_unblock_session(ddb_entry->sess); | ||
1236 | } else | ||
1237 | qla4xxx_relogin_device(ha, ddb_entry); | ||
1238 | } | ||
1239 | } | ||
1240 | } | ||
1241 | |||
1221 | void qla4xxx_wake_dpc(struct scsi_qla_host *ha) | 1242 | void qla4xxx_wake_dpc(struct scsi_qla_host *ha) |
1222 | { | 1243 | { |
1223 | if (ha->dpc_thread && | 1244 | if (ha->dpc_thread && |
@@ -1259,11 +1280,6 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
1259 | goto do_dpc_exit; | 1280 | goto do_dpc_exit; |
1260 | } | 1281 | } |
1261 | 1282 | ||
1262 | /* HBA is in the process of being permanently disabled. | ||
1263 | * Don't process anything */ | ||
1264 | if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) | ||
1265 | return; | ||
1266 | |||
1267 | if (is_qla8022(ha)) { | 1283 | if (is_qla8022(ha)) { |
1268 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { | 1284 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { |
1269 | qla4_8xxx_idc_lock(ha); | 1285 | qla4_8xxx_idc_lock(ha); |
@@ -1331,13 +1347,7 @@ dpc_post_reset_ha: | |||
1331 | if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { | 1347 | if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { |
1332 | if (!test_bit(AF_LINK_UP, &ha->flags)) { | 1348 | if (!test_bit(AF_LINK_UP, &ha->flags)) { |
1333 | /* ---- link down? --- */ | 1349 | /* ---- link down? --- */ |
1334 | list_for_each_entry_safe(ddb_entry, dtemp, | 1350 | qla4xxx_mark_all_devices_missing(ha); |
1335 | &ha->ddb_list, list) { | ||
1336 | if (atomic_read(&ddb_entry->state) == | ||
1337 | DDB_STATE_ONLINE) | ||
1338 | qla4xxx_mark_device_missing(ha, | ||
1339 | ddb_entry); | ||
1340 | } | ||
1341 | } else { | 1351 | } else { |
1342 | /* ---- link up? --- * | 1352 | /* ---- link up? --- * |
1343 | * F/W will auto login to all devices ONLY ONCE after | 1353 | * F/W will auto login to all devices ONLY ONCE after |
@@ -1346,30 +1356,7 @@ dpc_post_reset_ha: | |||
1346 | * manually relogin to devices when recovering from | 1356 | * manually relogin to devices when recovering from |
1347 | * connection failures, logouts, expired KATO, etc. */ | 1357 | * connection failures, logouts, expired KATO, etc. */ |
1348 | 1358 | ||
1349 | list_for_each_entry_safe(ddb_entry, dtemp, | 1359 | qla4xxx_relogin_all_devices(ha); |
1350 | &ha->ddb_list, list) { | ||
1351 | if ((atomic_read(&ddb_entry->state) == | ||
1352 | DDB_STATE_MISSING) || | ||
1353 | (atomic_read(&ddb_entry->state) == | ||
1354 | DDB_STATE_DEAD)) { | ||
1355 | if (ddb_entry->fw_ddb_device_state == | ||
1356 | DDB_DS_SESSION_ACTIVE) { | ||
1357 | atomic_set(&ddb_entry->state, | ||
1358 | DDB_STATE_ONLINE); | ||
1359 | ql4_printk(KERN_INFO, ha, | ||
1360 | "scsi%ld: %s: ddb[%d]" | ||
1361 | " marked ONLINE\n", | ||
1362 | ha->host_no, __func__, | ||
1363 | ddb_entry->fw_ddb_index); | ||
1364 | |||
1365 | iscsi_unblock_session( | ||
1366 | ddb_entry->sess); | ||
1367 | } else | ||
1368 | qla4xxx_relogin_device( | ||
1369 | ha, ddb_entry); | ||
1370 | } | ||
1371 | |||
1372 | } | ||
1373 | } | 1360 | } |
1374 | } | 1361 | } |
1375 | 1362 | ||
@@ -1630,6 +1617,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
1630 | uint8_t init_retry_count = 0; | 1617 | uint8_t init_retry_count = 0; |
1631 | char buf[34]; | 1618 | char buf[34]; |
1632 | struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; | 1619 | struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; |
1620 | uint32_t dev_state; | ||
1633 | 1621 | ||
1634 | if (pci_enable_device(pdev)) | 1622 | if (pci_enable_device(pdev)) |
1635 | return -1; | 1623 | return -1; |
@@ -1713,6 +1701,18 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
1713 | status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); | 1701 | status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); |
1714 | while ((!test_bit(AF_ONLINE, &ha->flags)) && | 1702 | while ((!test_bit(AF_ONLINE, &ha->flags)) && |
1715 | init_retry_count++ < MAX_INIT_RETRIES) { | 1703 | init_retry_count++ < MAX_INIT_RETRIES) { |
1704 | |||
1705 | if (is_qla8022(ha)) { | ||
1706 | qla4_8xxx_idc_lock(ha); | ||
1707 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
1708 | qla4_8xxx_idc_unlock(ha); | ||
1709 | if (dev_state == QLA82XX_DEV_FAILED) { | ||
1710 | ql4_printk(KERN_WARNING, ha, "%s: don't retry " | ||
1711 | "initialize adapter. H/W is in failed state\n", | ||
1712 | __func__); | ||
1713 | break; | ||
1714 | } | ||
1715 | } | ||
1716 | DEBUG2(printk("scsi: %s: retrying adapter initialization " | 1716 | DEBUG2(printk("scsi: %s: retrying adapter initialization " |
1717 | "(%d)\n", __func__, init_retry_count)); | 1717 | "(%d)\n", __func__, init_retry_count)); |
1718 | 1718 | ||
@@ -1815,6 +1815,44 @@ probe_disable_device: | |||
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | /** | 1817 | /** |
1818 | * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize | ||
1819 | * @ha: pointer to adapter structure | ||
1820 | * | ||
1821 | * Mark the other ISP-4xxx port to indicate that the driver is being removed, | ||
1822 | * so that the other port will not re-initialize while in the process of | ||
1823 | * removing the ha due to driver unload or hba hotplug. | ||
1824 | **/ | ||
1825 | static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) | ||
1826 | { | ||
1827 | struct scsi_qla_host *other_ha = NULL; | ||
1828 | struct pci_dev *other_pdev = NULL; | ||
1829 | int fn = ISP4XXX_PCI_FN_2; | ||
1830 | |||
1831 | /*iscsi function numbers for ISP4xxx is 1 and 3*/ | ||
1832 | if (PCI_FUNC(ha->pdev->devfn) & BIT_1) | ||
1833 | fn = ISP4XXX_PCI_FN_1; | ||
1834 | |||
1835 | other_pdev = | ||
1836 | pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), | ||
1837 | ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), | ||
1838 | fn)); | ||
1839 | |||
1840 | /* Get other_ha if other_pdev is valid and state is enable*/ | ||
1841 | if (other_pdev) { | ||
1842 | if (atomic_read(&other_pdev->enable_cnt)) { | ||
1843 | other_ha = pci_get_drvdata(other_pdev); | ||
1844 | if (other_ha) { | ||
1845 | set_bit(AF_HA_REMOVAL, &other_ha->flags); | ||
1846 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " | ||
1847 | "Prevent %s reinit\n", __func__, | ||
1848 | dev_name(&other_ha->pdev->dev))); | ||
1849 | } | ||
1850 | } | ||
1851 | pci_dev_put(other_pdev); | ||
1852 | } | ||
1853 | } | ||
1854 | |||
1855 | /** | ||
1818 | * qla4xxx_remove_adapter - calback function to remove adapter. | 1856 | * qla4xxx_remove_adapter - calback function to remove adapter. |
1819 | * @pci_dev: PCI device pointer | 1857 | * @pci_dev: PCI device pointer |
1820 | **/ | 1858 | **/ |
@@ -1824,7 +1862,8 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | |||
1824 | 1862 | ||
1825 | ha = pci_get_drvdata(pdev); | 1863 | ha = pci_get_drvdata(pdev); |
1826 | 1864 | ||
1827 | set_bit(AF_HBA_GOING_AWAY, &ha->flags); | 1865 | if (!is_qla8022(ha)) |
1866 | qla4xxx_prevent_other_port_reinit(ha); | ||
1828 | 1867 | ||
1829 | /* remove devs from iscsi_sessions to scsi_devices */ | 1868 | /* remove devs from iscsi_sessions to scsi_devices */ |
1830 | qla4xxx_free_ddb_list(ha); | 1869 | qla4xxx_free_ddb_list(ha); |
@@ -1868,10 +1907,15 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) | |||
1868 | { | 1907 | { |
1869 | struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); | 1908 | struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); |
1870 | struct ddb_entry *ddb = sess->dd_data; | 1909 | struct ddb_entry *ddb = sess->dd_data; |
1910 | int queue_depth = QL4_DEF_QDEPTH; | ||
1871 | 1911 | ||
1872 | sdev->hostdata = ddb; | 1912 | sdev->hostdata = ddb; |
1873 | sdev->tagged_supported = 1; | 1913 | sdev->tagged_supported = 1; |
1874 | scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); | 1914 | |
1915 | if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) | ||
1916 | queue_depth = ql4xmaxqdepth; | ||
1917 | |||
1918 | scsi_activate_tcq(sdev, queue_depth); | ||
1875 | return 0; | 1919 | return 0; |
1876 | } | 1920 | } |
1877 | 1921 | ||