15597088cSDongdong Hao // SPDX-License-Identifier: GPL-2.0
25597088cSDongdong Hao /*
35597088cSDongdong Hao * Copyright (C) 2026 LeapIO Tech Inc.
45597088cSDongdong Hao *
55597088cSDongdong Hao * LeapRAID storage and RAID controller driver.
65597088cSDongdong Hao */
75597088cSDongdong Hao #include <linux/module.h>
85597088cSDongdong Hao
95597088cSDongdong Hao #include "leapraid_func.h"
105597088cSDongdong Hao
115597088cSDongdong Hao static int poll_queues;
125597088cSDongdong Hao module_param(poll_queues, int, 0444);
135597088cSDongdong Hao MODULE_PARM_DESC(poll_queues,
145597088cSDongdong Hao "specifies the number of queues for io_uring poll mode.");
155597088cSDongdong Hao
165597088cSDongdong Hao static int max_msix_vectors = LEAPRAID_INVALID_MSIX_VECTORS;
175597088cSDongdong Hao module_param(max_msix_vectors, int, 0444);
185597088cSDongdong Hao MODULE_PARM_DESC(max_msix_vectors, "max msix vectors");
195597088cSDongdong Hao
205597088cSDongdong Hao static void leapraid_remove_device(struct leapraid_adapter *adapter,
215597088cSDongdong Hao struct leapraid_sas_dev *sas_dev);
225597088cSDongdong Hao static void leapraid_set_led(struct leapraid_adapter *adapter,
235597088cSDongdong Hao struct leapraid_sas_dev *sas_dev, bool on);
245597088cSDongdong Hao static void leapraid_ublk_io_dev(struct leapraid_adapter *adapter,
255597088cSDongdong Hao u64 sas_address,
265597088cSDongdong Hao struct leapraid_card_port *port);
275597088cSDongdong Hao static void leapraid_clear_cached_boot_dev(struct leapraid_adapter *adapter,
285597088cSDongdong Hao void *dev, u32 chnl);
295597088cSDongdong Hao static int leapraid_make_adapter_available(struct leapraid_adapter *adapter);
305597088cSDongdong Hao static void leapraid_sync_irqs_for_cleanup(struct leapraid_adapter *adapter);
315597088cSDongdong Hao static int leapraid_fw_log_init(struct leapraid_adapter *adapter);
325597088cSDongdong Hao static bool leapraid_should_skip_poll_work(struct leapraid_adapter *adapter);
335597088cSDongdong Hao static int leapraid_make_adapter_ready(struct leapraid_adapter *adapter,
345597088cSDongdong Hao enum reset_type type);
355597088cSDongdong Hao
leapraid_shost_in_recovery(struct Scsi_Host * shost)365597088cSDongdong Hao static noinline bool leapraid_shost_in_recovery(struct Scsi_Host *shost)
375597088cSDongdong Hao {
385597088cSDongdong Hao enum scsi_host_state state;
395597088cSDongdong Hao
40*4c461ee2SBart Van Assche state = scsi_get_host_state(shost);
415597088cSDongdong Hao return state == SHOST_RECOVERY ||
425597088cSDongdong Hao state == SHOST_CANCEL_RECOVERY ||
435597088cSDongdong Hao state == SHOST_DEL_RECOVERY ||
445597088cSDongdong Hao shost->tmf_in_progress;
455597088cSDongdong Hao }
465597088cSDongdong Hao
leapraid_is_end_dev(u32 dev_type)475597088cSDongdong Hao static inline bool leapraid_is_end_dev(u32 dev_type)
485597088cSDongdong Hao {
495597088cSDongdong Hao return (dev_type & LEAPRAID_DEVTYP_END_DEV) &&
505597088cSDongdong Hao ((dev_type & LEAPRAID_DEVTYP_SSP_TGT) ||
515597088cSDongdong Hao (dev_type & LEAPRAID_DEVTYP_STP_TGT) ||
525597088cSDongdong Hao (dev_type & LEAPRAID_DEVTYP_SATA_DEV));
535597088cSDongdong Hao }
545597088cSDongdong Hao
leapraid_pci_removed(struct leapraid_adapter * adapter)555597088cSDongdong Hao bool leapraid_pci_removed(struct leapraid_adapter *adapter)
565597088cSDongdong Hao {
575597088cSDongdong Hao struct pci_dev *pdev = adapter->pdev;
585597088cSDongdong Hao u32 vendor_id;
595597088cSDongdong Hao
605597088cSDongdong Hao if (pci_bus_read_config_dword(pdev->bus,
615597088cSDongdong Hao pdev->devfn,
625597088cSDongdong Hao PCI_VENDOR_ID,
635597088cSDongdong Hao &vendor_id))
645597088cSDongdong Hao return true;
655597088cSDongdong Hao
665597088cSDongdong Hao return (vendor_id & LEAPRAID_PCI_VENDOR_ID_MASK) !=
675597088cSDongdong Hao LEAPRAID_VENDOR_ID;
685597088cSDongdong Hao }
695597088cSDongdong Hao
leapraid_pci_active(struct leapraid_adapter * adapter)705597088cSDongdong Hao static bool leapraid_pci_active(struct leapraid_adapter *adapter)
715597088cSDongdong Hao {
725597088cSDongdong Hao return !(adapter->access_ctrl.pcie_recovering ||
735597088cSDongdong Hao leapraid_pci_removed(adapter));
745597088cSDongdong Hao }
755597088cSDongdong Hao
leapraid_get_reply_vaddr(struct leapraid_adapter * adapter,u32 rep_paddr)765597088cSDongdong Hao void *leapraid_get_reply_vaddr(struct leapraid_adapter *adapter, u32 rep_paddr)
775597088cSDongdong Hao {
785597088cSDongdong Hao if (!rep_paddr)
795597088cSDongdong Hao return NULL;
805597088cSDongdong Hao
815597088cSDongdong Hao return adapter->mem_desc.rep_msg +
825597088cSDongdong Hao (rep_paddr - (u32)adapter->mem_desc.rep_msg_dma);
835597088cSDongdong Hao }
845597088cSDongdong Hao
leapraid_get_task_desc(struct leapraid_adapter * adapter,u16 taskid)855597088cSDongdong Hao void *leapraid_get_task_desc(struct leapraid_adapter *adapter, u16 taskid)
865597088cSDongdong Hao {
875597088cSDongdong Hao return adapter->mem_desc.task_desc +
885597088cSDongdong Hao taskid * LEAPRAID_REQUEST_SIZE;
895597088cSDongdong Hao }
905597088cSDongdong Hao
leapraid_get_sense_buffer(struct leapraid_adapter * adapter,u16 taskid)915597088cSDongdong Hao void *leapraid_get_sense_buffer(struct leapraid_adapter *adapter, u16 taskid)
925597088cSDongdong Hao {
935597088cSDongdong Hao return adapter->mem_desc.sense_data +
945597088cSDongdong Hao (taskid - 1) * SCSI_SENSE_BUFFERSIZE;
955597088cSDongdong Hao }
965597088cSDongdong Hao
leapraid_get_sense_buffer_dma(struct leapraid_adapter * adapter,u16 taskid)975597088cSDongdong Hao __le32 leapraid_get_sense_buffer_dma(struct leapraid_adapter *adapter,
985597088cSDongdong Hao u16 taskid)
995597088cSDongdong Hao {
1005597088cSDongdong Hao return cpu_to_le32(adapter->mem_desc.sense_data_dma +
1015597088cSDongdong Hao ((taskid - 1) * SCSI_SENSE_BUFFERSIZE));
1025597088cSDongdong Hao }
1035597088cSDongdong Hao
leapraid_mask_int(struct leapraid_adapter * adapter)1045597088cSDongdong Hao void leapraid_mask_int(struct leapraid_adapter *adapter)
1055597088cSDongdong Hao {
1065597088cSDongdong Hao u32 reg;
1075597088cSDongdong Hao
1085597088cSDongdong Hao adapter->mask_int = 1;
1095597088cSDongdong Hao reg = leapraid_readl(&adapter->iomem_base->host_int_mask);
1105597088cSDongdong Hao reg |= LEAPRAID_TO_SYS_DB_MASK + LEAPRAID_REPLY_INT_MASK +
1115597088cSDongdong Hao LEAPRAID_RESET_IRQ_MASK;
1125597088cSDongdong Hao writel(reg, &adapter->iomem_base->host_int_mask);
1135597088cSDongdong Hao leapraid_readl(&adapter->iomem_base->host_int_mask);
1145597088cSDongdong Hao }
1155597088cSDongdong Hao
leapraid_unmask_int(struct leapraid_adapter * adapter)1165597088cSDongdong Hao void leapraid_unmask_int(struct leapraid_adapter *adapter)
1175597088cSDongdong Hao {
1185597088cSDongdong Hao u32 reg;
1195597088cSDongdong Hao
1205597088cSDongdong Hao reg = leapraid_readl(&adapter->iomem_base->host_int_mask);
1215597088cSDongdong Hao reg &= ~LEAPRAID_REPLY_INT_MASK;
1225597088cSDongdong Hao writel(reg, &adapter->iomem_base->host_int_mask);
1235597088cSDongdong Hao adapter->mask_int = 0;
1245597088cSDongdong Hao }
1255597088cSDongdong Hao
leapraid_overheat_suspend(struct leapraid_adapter * adapter)1265597088cSDongdong Hao static void leapraid_overheat_suspend(struct leapraid_adapter *adapter)
1275597088cSDongdong Hao {
1285597088cSDongdong Hao struct workqueue_struct *wq;
1295597088cSDongdong Hao struct Scsi_Host *shost;
1305597088cSDongdong Hao struct pci_dev *pdev;
1315597088cSDongdong Hao
1325597088cSDongdong Hao if (!adapter)
1335597088cSDongdong Hao return;
1345597088cSDongdong Hao
1355597088cSDongdong Hao pdev = adapter->pdev;
1365597088cSDongdong Hao shost = pci_get_drvdata(pdev);
1375597088cSDongdong Hao if (!shost) {
1385597088cSDongdong Hao dev_warn(&pdev->dev,
1395597088cSDongdong Hao "Overheat suspend failed, invalid host or adapter\n");
1405597088cSDongdong Hao return;
1415597088cSDongdong Hao }
1425597088cSDongdong Hao
1435597088cSDongdong Hao wq = adapter->overheat_desc.fault_overheat_wq;
1445597088cSDongdong Hao if (!wq)
1455597088cSDongdong Hao return;
1465597088cSDongdong Hao
1475597088cSDongdong Hao if (atomic_cmpxchg(&adapter->overheat_desc.thermal_alert, 0, 1))
1485597088cSDongdong Hao return;
1495597088cSDongdong Hao
1505597088cSDongdong Hao queue_work(wq, &adapter->overheat_desc.fault_overheat_work);
1515597088cSDongdong Hao }
1525597088cSDongdong Hao
leapraid_stop_adapter_on_fault(struct leapraid_adapter * adapter,u32 db)1535597088cSDongdong Hao static void leapraid_stop_adapter_on_fault(struct leapraid_adapter *adapter,
1545597088cSDongdong Hao u32 db)
1555597088cSDongdong Hao {
1565597088cSDongdong Hao u32 adapter_state = db & LEAPRAID_DB_MASK;
1575597088cSDongdong Hao bool fault_1 = false;
1585597088cSDongdong Hao bool fault_2 = false;
1595597088cSDongdong Hao
1605597088cSDongdong Hao fault_1 = adapter_state == LEAPRAID_DB_MASK;
1615597088cSDongdong Hao fault_2 = adapter_state == LEAPRAID_DB_FAULT &&
1625597088cSDongdong Hao (db & LEAPRAID_DB_DATA_MASK) == LEAPRAID_DB_OVER_TEMPERATURE;
1635597088cSDongdong Hao
1645597088cSDongdong Hao if (!fault_1 && !fault_2)
1655597088cSDongdong Hao return;
1665597088cSDongdong Hao
1675597088cSDongdong Hao if (fault_1)
1685597088cSDongdong Hao dev_err(&adapter->pdev->dev,
1695597088cSDongdong Hao "%s: Doorbell status 0xFFFF!\n", __func__);
1705597088cSDongdong Hao else
1715597088cSDongdong Hao dev_err(&adapter->pdev->dev,
1725597088cSDongdong Hao "%s: Adapter overheating detected!\n", __func__);
1735597088cSDongdong Hao
1745597088cSDongdong Hao leapraid_overheat_suspend(adapter);
1755597088cSDongdong Hao }
1765597088cSDongdong Hao
leapraid_get_adapter_state(struct leapraid_adapter * adapter)1775597088cSDongdong Hao u32 leapraid_get_adapter_state(struct leapraid_adapter *adapter)
1785597088cSDongdong Hao {
1795597088cSDongdong Hao u32 db;
1805597088cSDongdong Hao u32 adapter_state;
1815597088cSDongdong Hao
1825597088cSDongdong Hao db = leapraid_readl(&adapter->iomem_base->db);
1835597088cSDongdong Hao adapter_state = db & LEAPRAID_DB_MASK;
1845597088cSDongdong Hao leapraid_stop_adapter_on_fault(adapter, db);
1855597088cSDongdong Hao return adapter_state;
1865597088cSDongdong Hao }
1875597088cSDongdong Hao
leapraid_wait_adapter_ready(struct leapraid_adapter * adapter)1885597088cSDongdong Hao static bool leapraid_wait_adapter_ready(struct leapraid_adapter *adapter)
1895597088cSDongdong Hao {
1905597088cSDongdong Hao u32 cur_state;
1915597088cSDongdong Hao u32 cnt;
1925597088cSDongdong Hao
1935597088cSDongdong Hao for (cnt = LEAPRAID_ADAPTER_READY_MAX_RETRY; cnt > 0; cnt--) {
1945597088cSDongdong Hao cur_state = leapraid_get_adapter_state(adapter);
1955597088cSDongdong Hao
1965597088cSDongdong Hao if (cur_state == LEAPRAID_DB_READY)
1975597088cSDongdong Hao return true;
1985597088cSDongdong Hao if (cur_state == LEAPRAID_DB_FAULT)
1995597088cSDongdong Hao break;
2005597088cSDongdong Hao usleep_range(LEAPRAID_ADAPTER_READY_SLEEP_MIN_US,
2015597088cSDongdong Hao LEAPRAID_ADAPTER_READY_SLEEP_MAX_US);
2025597088cSDongdong Hao }
2035597088cSDongdong Hao
2045597088cSDongdong Hao return false;
2055597088cSDongdong Hao }
2065597088cSDongdong Hao
leapraid_db_wait_int_host(struct leapraid_adapter * adapter)2075597088cSDongdong Hao static int leapraid_db_wait_int_host(struct leapraid_adapter *adapter)
2085597088cSDongdong Hao {
2095597088cSDongdong Hao u32 cnt;
2105597088cSDongdong Hao
2115597088cSDongdong Hao for (cnt = LEAPRAID_DB_WAIT_MAX_RETRY; cnt > 0; cnt--) {
2125597088cSDongdong Hao if (leapraid_readl(&adapter->iomem_base->host_int_status) &
2135597088cSDongdong Hao LEAPRAID_ADAPTER2HOST_DB_STATUS)
2145597088cSDongdong Hao return 0;
2155597088cSDongdong Hao
2165597088cSDongdong Hao udelay(LEAPRAID_DB_WAIT_DELAY_US);
2175597088cSDongdong Hao }
2185597088cSDongdong Hao
2195597088cSDongdong Hao return -EFAULT;
2205597088cSDongdong Hao }
2215597088cSDongdong Hao
leapraid_db_wait_ack_and_clear_int(struct leapraid_adapter * adapter)2225597088cSDongdong Hao static int leapraid_db_wait_ack_and_clear_int(struct leapraid_adapter *adapter)
2235597088cSDongdong Hao {
2245597088cSDongdong Hao u32 adapter_state;
2255597088cSDongdong Hao u32 int_status;
2265597088cSDongdong Hao u32 cnt;
2275597088cSDongdong Hao
2285597088cSDongdong Hao for (cnt = LEAPRAID_ADAPTER_READY_MAX_RETRY; cnt > 0; cnt--) {
2295597088cSDongdong Hao int_status =
2305597088cSDongdong Hao leapraid_readl(&adapter->iomem_base->host_int_status);
2315597088cSDongdong Hao
2325597088cSDongdong Hao if (int_status == 0xFFFFFFFF)
2335597088cSDongdong Hao return -EFAULT;
2345597088cSDongdong Hao
2355597088cSDongdong Hao if (!(int_status & LEAPRAID_HOST2ADAPTER_DB_STATUS))
2365597088cSDongdong Hao return 0;
2375597088cSDongdong Hao
2385597088cSDongdong Hao if (int_status & LEAPRAID_ADAPTER2HOST_DB_STATUS) {
2395597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
2405597088cSDongdong Hao if (adapter_state == LEAPRAID_DB_FAULT)
2415597088cSDongdong Hao return -EFAULT;
2425597088cSDongdong Hao }
2435597088cSDongdong Hao
2445597088cSDongdong Hao usleep_range(LEAPRAID_ADAPTER_READY_SLEEP_MIN_US,
2455597088cSDongdong Hao LEAPRAID_ADAPTER_READY_SLEEP_MAX_US);
2465597088cSDongdong Hao }
2475597088cSDongdong Hao
2485597088cSDongdong Hao return -EFAULT;
2495597088cSDongdong Hao }
2505597088cSDongdong Hao
leapraid_handshake_func(struct leapraid_adapter * adapter,int req_bytes,u32 * req,int rep_bytes,u16 * rep)2515597088cSDongdong Hao static int leapraid_handshake_func(struct leapraid_adapter *adapter,
2525597088cSDongdong Hao int req_bytes, u32 *req,
2535597088cSDongdong Hao int rep_bytes, u16 *rep)
2545597088cSDongdong Hao {
2555597088cSDongdong Hao int failed, i;
2565597088cSDongdong Hao
2575597088cSDongdong Hao if (leapraid_readl(&adapter->iomem_base->db) & LEAPRAID_DB_USED) {
2585597088cSDongdong Hao dev_err(&adapter->pdev->dev, "doorbell used\n");
2595597088cSDongdong Hao return -EFAULT;
2605597088cSDongdong Hao }
2615597088cSDongdong Hao
2625597088cSDongdong Hao if (leapraid_readl(&adapter->iomem_base->host_int_status) &
2635597088cSDongdong Hao LEAPRAID_ADAPTER2HOST_DB_STATUS)
2645597088cSDongdong Hao writel(0, &adapter->iomem_base->host_int_status);
2655597088cSDongdong Hao
2665597088cSDongdong Hao writel(((LEAPRAID_FUNC_HANDSHAKE << LEAPRAID_DB_FUNC_SHIFT) |
2675597088cSDongdong Hao ((req_bytes / LEAPRAID_DWORDS_BYTE_SIZE) <<
2685597088cSDongdong Hao LEAPRAID_DB_ADD_DWORDS_SHIFT)),
2695597088cSDongdong Hao &adapter->iomem_base->db);
2705597088cSDongdong Hao
2715597088cSDongdong Hao if (leapraid_db_wait_int_host(adapter)) {
2725597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%d: Wait db interrupt timeout\n",
2735597088cSDongdong Hao __LINE__);
2745597088cSDongdong Hao return -EFAULT;
2755597088cSDongdong Hao }
2765597088cSDongdong Hao
2775597088cSDongdong Hao writel(0, &adapter->iomem_base->host_int_status);
2785597088cSDongdong Hao
2795597088cSDongdong Hao if (leapraid_db_wait_ack_and_clear_int(adapter)) {
2805597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%d: Wait ack failure\n",
2815597088cSDongdong Hao __LINE__);
2825597088cSDongdong Hao return -EFAULT;
2835597088cSDongdong Hao }
2845597088cSDongdong Hao
2855597088cSDongdong Hao for (i = 0, failed = 0;
2865597088cSDongdong Hao i < req_bytes / LEAPRAID_DWORDS_BYTE_SIZE && !failed;
2875597088cSDongdong Hao i++) {
2885597088cSDongdong Hao writel((u32)req[i], &adapter->iomem_base->db);
2895597088cSDongdong Hao if (leapraid_db_wait_ack_and_clear_int(adapter))
2905597088cSDongdong Hao failed = 1;
2915597088cSDongdong Hao }
2925597088cSDongdong Hao if (failed) {
2935597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%d: Wait ack failure\n",
2945597088cSDongdong Hao __LINE__);
2955597088cSDongdong Hao return -EFAULT;
2965597088cSDongdong Hao }
2975597088cSDongdong Hao
2985597088cSDongdong Hao for (i = 0; i < rep_bytes / LEAPRAID_WORD_BYTE_SIZE; i++) {
2995597088cSDongdong Hao if (leapraid_db_wait_int_host(adapter)) {
3005597088cSDongdong Hao dev_err(&adapter->pdev->dev,
3015597088cSDongdong Hao "%d: Wait db interrupt timeout\n", __LINE__);
3025597088cSDongdong Hao return -EFAULT;
3035597088cSDongdong Hao }
3045597088cSDongdong Hao rep[i] = (u16)(leapraid_readl(&adapter->iomem_base->db)
3055597088cSDongdong Hao & LEAPRAID_DB_DATA_MASK);
3065597088cSDongdong Hao writel(0, &adapter->iomem_base->host_int_status);
3075597088cSDongdong Hao }
3085597088cSDongdong Hao
3095597088cSDongdong Hao if (leapraid_db_wait_int_host(adapter)) {
3105597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%d: Wait db interrupt timeout\n",
3115597088cSDongdong Hao __LINE__);
3125597088cSDongdong Hao return -EFAULT;
3135597088cSDongdong Hao }
3145597088cSDongdong Hao
3155597088cSDongdong Hao writel(0, &adapter->iomem_base->host_int_status);
3165597088cSDongdong Hao
3175597088cSDongdong Hao return 0;
3185597088cSDongdong Hao }
3195597088cSDongdong Hao
leapraid_check_adapter_is_op(struct leapraid_adapter * adapter,int wait,const char * caller)3205597088cSDongdong Hao int leapraid_check_adapter_is_op(struct leapraid_adapter *adapter, int wait,
3215597088cSDongdong Hao const char *caller)
3225597088cSDongdong Hao {
3235597088cSDongdong Hao int wait_count;
3245597088cSDongdong Hao
3255597088cSDongdong Hao for (wait_count = wait; wait_count > 0; wait_count--) {
3265597088cSDongdong Hao if (READ_ONCE(adapter->access_ctrl.host_removing)) {
3275597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
3285597088cSDongdong Hao "%s: Host is removing\n", caller);
3295597088cSDongdong Hao return -EFAULT;
3305597088cSDongdong Hao }
3315597088cSDongdong Hao
3325597088cSDongdong Hao if (leapraid_pci_removed(adapter)) {
3335597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
3345597088cSDongdong Hao "%s: PCI device removed\n", __func__);
3355597088cSDongdong Hao return -EFAULT;
3365597088cSDongdong Hao }
3375597088cSDongdong Hao
3385597088cSDongdong Hao if (leapraid_get_adapter_state(adapter) ==
3395597088cSDongdong Hao LEAPRAID_DB_OPERATIONAL)
3405597088cSDongdong Hao return 0;
3415597088cSDongdong Hao
3425597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
3435597088cSDongdong Hao "%s: Wait for adapter to become op status(cnt=%d)\n",
3445597088cSDongdong Hao caller, wait - wait_count);
3455597088cSDongdong Hao
3465597088cSDongdong Hao ssleep(1);
3475597088cSDongdong Hao }
3485597088cSDongdong Hao
3495597088cSDongdong Hao dev_err(&adapter->pdev->dev,
3505597088cSDongdong Hao "%s: Adapter failed to become op state, last state=%d\n",
3515597088cSDongdong Hao caller, leapraid_get_adapter_state(adapter));
3525597088cSDongdong Hao
3535597088cSDongdong Hao return -EFAULT;
3545597088cSDongdong Hao }
3555597088cSDongdong Hao
leapraid_get_io_tracker_from_taskid(struct leapraid_adapter * adapter,u16 taskid)3565597088cSDongdong Hao struct leapraid_io_req_tracker *leapraid_get_io_tracker_from_taskid(
3575597088cSDongdong Hao struct leapraid_adapter *adapter, u16 taskid)
3585597088cSDongdong Hao {
3595597088cSDongdong Hao struct scsi_cmnd *scmd;
3605597088cSDongdong Hao
3615597088cSDongdong Hao if (WARN_ON(!taskid))
3625597088cSDongdong Hao return NULL;
3635597088cSDongdong Hao
3645597088cSDongdong Hao if (WARN_ON(taskid > adapter->shost->can_queue))
3655597088cSDongdong Hao return NULL;
3665597088cSDongdong Hao
3675597088cSDongdong Hao scmd = leapraid_get_scmd_from_taskid(adapter, taskid);
3685597088cSDongdong Hao if (scmd)
3695597088cSDongdong Hao return scsi_cmd_priv(scmd);
3705597088cSDongdong Hao
3715597088cSDongdong Hao return NULL;
3725597088cSDongdong Hao }
3735597088cSDongdong Hao
leapraid_get_cb_idx(struct leapraid_adapter * adapter,u16 taskid)3745597088cSDongdong Hao static u8 leapraid_get_cb_idx(struct leapraid_adapter *adapter, u16 taskid)
3755597088cSDongdong Hao {
3765597088cSDongdong Hao struct leapraid_driver_cmd *sp_cmd;
3775597088cSDongdong Hao u8 cb_idx = 0xFF;
3785597088cSDongdong Hao
3795597088cSDongdong Hao if (WARN_ON(!taskid))
3805597088cSDongdong Hao return cb_idx;
3815597088cSDongdong Hao
3825597088cSDongdong Hao list_for_each_entry(sp_cmd, &adapter->driver_cmds.special_cmd_list,
3835597088cSDongdong Hao list)
3845597088cSDongdong Hao if (taskid == sp_cmd->taskid ||
3855597088cSDongdong Hao taskid == sp_cmd->hp_taskid ||
3865597088cSDongdong Hao taskid == sp_cmd->inter_taskid)
3875597088cSDongdong Hao return sp_cmd->cb_idx;
3885597088cSDongdong Hao
3895597088cSDongdong Hao WARN_ON(cb_idx == 0xFF);
3905597088cSDongdong Hao return cb_idx;
3915597088cSDongdong Hao }
3925597088cSDongdong Hao
leapraid_get_scmd_from_taskid(struct leapraid_adapter * adapter,u16 taskid)3935597088cSDongdong Hao struct scsi_cmnd *leapraid_get_scmd_from_taskid(
3945597088cSDongdong Hao struct leapraid_adapter *adapter,
3955597088cSDongdong Hao u16 taskid)
3965597088cSDongdong Hao {
3975597088cSDongdong Hao struct leapraid_scsiio_req *leap_mpi_req;
3985597088cSDongdong Hao struct leapraid_io_req_tracker *st;
3995597088cSDongdong Hao struct scsi_cmnd *scmd;
4005597088cSDongdong Hao u32 uniq_tag;
4015597088cSDongdong Hao
4025597088cSDongdong Hao if (taskid <= 0 || taskid > adapter->shost->can_queue)
4035597088cSDongdong Hao return NULL;
4045597088cSDongdong Hao
4055597088cSDongdong Hao uniq_tag = adapter->mem_desc.taskid_to_uniq_tag[taskid - 1] <<
4065597088cSDongdong Hao BLK_MQ_UNIQUE_TAG_BITS | (taskid - 1);
4075597088cSDongdong Hao leap_mpi_req = leapraid_get_task_desc(adapter, taskid);
4085597088cSDongdong Hao if (!leap_mpi_req->dev_hdl)
4095597088cSDongdong Hao return NULL;
4105597088cSDongdong Hao
4115597088cSDongdong Hao scmd = scsi_host_find_tag(adapter->shost, uniq_tag);
4125597088cSDongdong Hao if (scmd) {
4135597088cSDongdong Hao st = scsi_cmd_priv(scmd);
4145597088cSDongdong Hao if (st && st->taskid == taskid)
4155597088cSDongdong Hao return scmd;
4165597088cSDongdong Hao }
4175597088cSDongdong Hao
4185597088cSDongdong Hao return NULL;
4195597088cSDongdong Hao }
4205597088cSDongdong Hao
leapraid_alloc_scsiio_taskid(struct leapraid_adapter * adapter,struct scsi_cmnd * scmd)4215597088cSDongdong Hao u16 leapraid_alloc_scsiio_taskid(struct leapraid_adapter *adapter,
4225597088cSDongdong Hao struct scsi_cmnd *scmd)
4235597088cSDongdong Hao {
4245597088cSDongdong Hao struct leapraid_io_req_tracker *request;
4255597088cSDongdong Hao u16 taskid;
4265597088cSDongdong Hao u32 tag = scsi_cmd_to_rq(scmd)->tag;
4275597088cSDongdong Hao u32 unique_tag;
4285597088cSDongdong Hao
4295597088cSDongdong Hao unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
4305597088cSDongdong Hao tag = blk_mq_unique_tag_to_tag(unique_tag);
4315597088cSDongdong Hao adapter->mem_desc.taskid_to_uniq_tag[tag] =
4325597088cSDongdong Hao blk_mq_unique_tag_to_hwq(unique_tag);
4335597088cSDongdong Hao
4345597088cSDongdong Hao request = scsi_cmd_priv(scmd);
4355597088cSDongdong Hao taskid = tag + 1;
4365597088cSDongdong Hao request->taskid = taskid;
4375597088cSDongdong Hao request->scmd = scmd;
4385597088cSDongdong Hao return taskid;
4395597088cSDongdong Hao }
4405597088cSDongdong Hao
leapraid_check_pending_io(struct leapraid_adapter * adapter)4415597088cSDongdong Hao static void leapraid_check_pending_io(struct leapraid_adapter *adapter)
4425597088cSDongdong Hao {
4435597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering &&
4445597088cSDongdong Hao adapter->reset_desc.pending_io_cnt) {
4455597088cSDongdong Hao if (adapter->reset_desc.pending_io_cnt == 1)
4465597088cSDongdong Hao wake_up(&adapter->reset_desc.reset_wait_queue);
4475597088cSDongdong Hao adapter->reset_desc.pending_io_cnt--;
4485597088cSDongdong Hao }
4495597088cSDongdong Hao }
4505597088cSDongdong Hao
leapraid_clear_io_tracker(struct leapraid_adapter * adapter,struct leapraid_io_req_tracker * io_tracker)4515597088cSDongdong Hao static void leapraid_clear_io_tracker(
4525597088cSDongdong Hao struct leapraid_adapter *adapter,
4535597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker)
4545597088cSDongdong Hao {
4555597088cSDongdong Hao if (!io_tracker)
4565597088cSDongdong Hao return;
4575597088cSDongdong Hao
4585597088cSDongdong Hao if (WARN_ON(io_tracker->taskid == 0))
4595597088cSDongdong Hao return;
4605597088cSDongdong Hao
4615597088cSDongdong Hao io_tracker->scmd = NULL;
4625597088cSDongdong Hao }
4635597088cSDongdong Hao
leapraid_is_fixed_taskid(struct leapraid_adapter * adapter,u16 taskid)4645597088cSDongdong Hao static bool leapraid_is_fixed_taskid(struct leapraid_adapter *adapter,
4655597088cSDongdong Hao u16 taskid)
4665597088cSDongdong Hao {
4675597088cSDongdong Hao struct leapraid_driver_cmds *driver_cmds = &adapter->driver_cmds;
4685597088cSDongdong Hao
4695597088cSDongdong Hao return (taskid == driver_cmds->ctl_cmd.taskid ||
4705597088cSDongdong Hao taskid == driver_cmds->tm_cmd.hp_taskid ||
4715597088cSDongdong Hao taskid == driver_cmds->ctl_cmd.hp_taskid ||
4725597088cSDongdong Hao taskid == driver_cmds->scan_dev_cmd.inter_taskid ||
4735597088cSDongdong Hao taskid == driver_cmds->transport_cmd.inter_taskid ||
4745597088cSDongdong Hao taskid == driver_cmds->cfg_op_cmd.inter_taskid ||
4755597088cSDongdong Hao taskid == driver_cmds->enc_cmd.inter_taskid ||
4765597088cSDongdong Hao taskid == driver_cmds->notify_event_cmd.inter_taskid);
4775597088cSDongdong Hao }
4785597088cSDongdong Hao
leapraid_free_taskid(struct leapraid_adapter * adapter,u16 taskid)4795597088cSDongdong Hao void leapraid_free_taskid(struct leapraid_adapter *adapter, u16 taskid)
4805597088cSDongdong Hao {
4815597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker;
4825597088cSDongdong Hao void *task_desc;
4835597088cSDongdong Hao
4845597088cSDongdong Hao if (leapraid_is_fixed_taskid(adapter, taskid))
4855597088cSDongdong Hao return;
4865597088cSDongdong Hao
4875597088cSDongdong Hao if (taskid <= adapter->shost->can_queue) {
4885597088cSDongdong Hao io_tracker = leapraid_get_io_tracker_from_taskid(adapter,
4895597088cSDongdong Hao taskid);
4905597088cSDongdong Hao if (!io_tracker) {
4915597088cSDongdong Hao leapraid_check_pending_io(adapter);
4925597088cSDongdong Hao return;
4935597088cSDongdong Hao }
4945597088cSDongdong Hao
4955597088cSDongdong Hao task_desc = leapraid_get_task_desc(adapter, taskid);
4965597088cSDongdong Hao memset(task_desc, 0, LEAPRAID_REQUEST_SIZE);
4975597088cSDongdong Hao leapraid_clear_io_tracker(adapter, io_tracker);
4985597088cSDongdong Hao leapraid_check_pending_io(adapter);
4995597088cSDongdong Hao adapter->mem_desc.taskid_to_uniq_tag[taskid - 1] = 0xFFFF;
5005597088cSDongdong Hao }
5015597088cSDongdong Hao }
5025597088cSDongdong Hao
leapraid_get_msix_idx(struct leapraid_adapter * adapter,struct scsi_cmnd * scmd)5035597088cSDongdong Hao static u8 leapraid_get_msix_idx(struct leapraid_adapter *adapter,
5045597088cSDongdong Hao struct scsi_cmnd *scmd)
5055597088cSDongdong Hao {
5065597088cSDongdong Hao if (scmd && adapter->shost->nr_hw_queues > 1) {
5075597088cSDongdong Hao u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
5085597088cSDongdong Hao
5095597088cSDongdong Hao return blk_mq_unique_tag_to_hwq(tag);
5105597088cSDongdong Hao }
5115597088cSDongdong Hao return adapter->notification_desc.msix_cpu_map[raw_smp_processor_id()];
5125597088cSDongdong Hao }
5135597088cSDongdong Hao
leapraid_get_and_set_msix_idx_from_taskid(struct leapraid_adapter * adapter,u16 taskid)5145597088cSDongdong Hao static u8 leapraid_get_and_set_msix_idx_from_taskid(
5155597088cSDongdong Hao struct leapraid_adapter *adapter, u16 taskid)
5165597088cSDongdong Hao {
5175597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker = NULL;
5185597088cSDongdong Hao
5195597088cSDongdong Hao if (taskid <= adapter->shost->can_queue)
5205597088cSDongdong Hao io_tracker = leapraid_get_io_tracker_from_taskid(adapter,
5215597088cSDongdong Hao taskid);
5225597088cSDongdong Hao
5235597088cSDongdong Hao if (!io_tracker)
5245597088cSDongdong Hao return leapraid_get_msix_idx(adapter, NULL);
5255597088cSDongdong Hao
5265597088cSDongdong Hao io_tracker->msix_io = leapraid_get_msix_idx(adapter, io_tracker->scmd);
5275597088cSDongdong Hao
5285597088cSDongdong Hao return io_tracker->msix_io;
5295597088cSDongdong Hao }
5305597088cSDongdong Hao
leapraid_fire_scsi_io(struct leapraid_adapter * adapter,u16 taskid,u16 handle)5315597088cSDongdong Hao void leapraid_fire_scsi_io(struct leapraid_adapter *adapter, u16 taskid,
5325597088cSDongdong Hao u16 handle)
5335597088cSDongdong Hao {
5345597088cSDongdong Hao struct leapraid_atomic_req_desc desc;
5355597088cSDongdong Hao
5365597088cSDongdong Hao desc.flg = LEAPRAID_REQ_DESC_FLG_SCSI_IO;
5375597088cSDongdong Hao desc.msix_idx = leapraid_get_and_set_msix_idx_from_taskid(adapter,
5385597088cSDongdong Hao taskid);
5395597088cSDongdong Hao desc.taskid = cpu_to_le16(taskid);
5405597088cSDongdong Hao writel((__force u32)cpu_to_le32(*((u32 *)&desc)),
5415597088cSDongdong Hao &adapter->iomem_base->atomic_req_desc_post);
5425597088cSDongdong Hao }
5435597088cSDongdong Hao
leapraid_fire_hpr_task(struct leapraid_adapter * adapter,u16 taskid,u16 msix_task)5445597088cSDongdong Hao void leapraid_fire_hpr_task(struct leapraid_adapter *adapter, u16 taskid,
5455597088cSDongdong Hao u16 msix_task)
5465597088cSDongdong Hao {
5475597088cSDongdong Hao struct leapraid_atomic_req_desc desc;
5485597088cSDongdong Hao
5495597088cSDongdong Hao desc.flg = LEAPRAID_REQ_DESC_FLG_HPR;
5505597088cSDongdong Hao desc.msix_idx = msix_task;
5515597088cSDongdong Hao desc.taskid = cpu_to_le16(taskid);
5525597088cSDongdong Hao writel((__force u32)cpu_to_le32(*((u32 *)&desc)),
5535597088cSDongdong Hao &adapter->iomem_base->atomic_req_desc_post);
5545597088cSDongdong Hao }
5555597088cSDongdong Hao
leapraid_fire_task(struct leapraid_adapter * adapter,u16 taskid)5565597088cSDongdong Hao void leapraid_fire_task(struct leapraid_adapter *adapter, u16 taskid)
5575597088cSDongdong Hao {
5585597088cSDongdong Hao struct leapraid_atomic_req_desc desc;
5595597088cSDongdong Hao
5605597088cSDongdong Hao desc.flg = LEAPRAID_REQ_DESC_FLG_DFLT_TYPE;
5615597088cSDongdong Hao desc.msix_idx = leapraid_get_and_set_msix_idx_from_taskid(adapter,
5625597088cSDongdong Hao taskid);
5635597088cSDongdong Hao desc.taskid = cpu_to_le16(taskid);
5645597088cSDongdong Hao writel((__force u32)cpu_to_le32(*((u32 *)&desc)),
5655597088cSDongdong Hao &adapter->iomem_base->atomic_req_desc_post);
5665597088cSDongdong Hao }
5675597088cSDongdong Hao
leapraid_clean_active_scsi_cmds(struct leapraid_adapter * adapter)5685597088cSDongdong Hao void leapraid_clean_active_scsi_cmds(struct leapraid_adapter *adapter)
5695597088cSDongdong Hao {
5705597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker;
5715597088cSDongdong Hao struct scsi_cmnd *scmd;
5725597088cSDongdong Hao void *task_desc;
5735597088cSDongdong Hao u16 taskid;
5745597088cSDongdong Hao
5755597088cSDongdong Hao leapraid_sync_irqs_for_cleanup(adapter);
5765597088cSDongdong Hao
5775597088cSDongdong Hao for (taskid = 1; taskid <= adapter->shost->can_queue; taskid++) {
5785597088cSDongdong Hao scmd = leapraid_get_scmd_from_taskid(adapter, taskid);
5795597088cSDongdong Hao if (!scmd)
5805597088cSDongdong Hao continue;
5815597088cSDongdong Hao
5825597088cSDongdong Hao io_tracker = scsi_cmd_priv(scmd);
5835597088cSDongdong Hao if (io_tracker && io_tracker->taskid == 0)
5845597088cSDongdong Hao continue;
5855597088cSDongdong Hao
5865597088cSDongdong Hao scsi_dma_unmap(scmd);
5875597088cSDongdong Hao task_desc = leapraid_get_task_desc(adapter, taskid);
5885597088cSDongdong Hao memset(task_desc, 0, LEAPRAID_REQUEST_SIZE);
5895597088cSDongdong Hao leapraid_clear_io_tracker(adapter, io_tracker);
5905597088cSDongdong Hao if (!leapraid_pci_active(adapter) ||
5915597088cSDongdong Hao adapter->reset_desc.adapter_reset_results != 0 ||
5925597088cSDongdong Hao atomic_read(&adapter->overheat_desc.thermal_alert) ||
5935597088cSDongdong Hao adapter->access_ctrl.host_removing)
5945597088cSDongdong Hao scmd->result = DID_NO_CONNECT << 16;
5955597088cSDongdong Hao else
5965597088cSDongdong Hao scmd->result = DID_RESET << LEAPRAID_SCSI_HOST_SHIFT;
5975597088cSDongdong Hao scsi_done(scmd);
5985597088cSDongdong Hao }
5995597088cSDongdong Hao }
6005597088cSDongdong Hao
leapraid_clean_active_driver_cmd(struct leapraid_driver_cmd * cmd)6015597088cSDongdong Hao static void leapraid_clean_active_driver_cmd(struct leapraid_driver_cmd *cmd)
6025597088cSDongdong Hao {
6035597088cSDongdong Hao if (cmd->status & LEAPRAID_CMD_PENDING) {
6045597088cSDongdong Hao cmd->status |= LEAPRAID_CMD_RESET;
6055597088cSDongdong Hao complete(&cmd->done);
6065597088cSDongdong Hao }
6075597088cSDongdong Hao }
6085597088cSDongdong Hao
leapraid_clean_active_driver_cmds(struct leapraid_adapter * adapter)6095597088cSDongdong Hao static void leapraid_clean_active_driver_cmds(struct leapraid_adapter *adapter)
6105597088cSDongdong Hao {
6115597088cSDongdong Hao struct leapraid_driver_cmds *driver_cmds;
6125597088cSDongdong Hao
6135597088cSDongdong Hao driver_cmds = &adapter->driver_cmds;
6145597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->tm_cmd);
6155597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->transport_cmd);
6165597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->enc_cmd);
6175597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->notify_event_cmd);
6185597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->cfg_op_cmd);
6195597088cSDongdong Hao leapraid_clean_active_driver_cmd(&driver_cmds->ctl_cmd);
6205597088cSDongdong Hao
6215597088cSDongdong Hao if (driver_cmds->scan_dev_cmd.status & LEAPRAID_CMD_PENDING) {
6225597088cSDongdong Hao adapter->scan_dev_desc.scan_dev_failed = 1;
6235597088cSDongdong Hao driver_cmds->scan_dev_cmd.status |= LEAPRAID_CMD_RESET;
6245597088cSDongdong Hao if (adapter->scan_dev_desc.driver_loading) {
6255597088cSDongdong Hao adapter->scan_dev_desc.scan_start_failed =
6265597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_INTERNAL_ERROR;
6275597088cSDongdong Hao adapter->scan_dev_desc.scan_start = 0;
6285597088cSDongdong Hao } else {
6295597088cSDongdong Hao complete(&driver_cmds->scan_dev_cmd.done);
6305597088cSDongdong Hao }
6315597088cSDongdong Hao }
6325597088cSDongdong Hao }
6335597088cSDongdong Hao
leapraid_clean_active_cmds(struct leapraid_adapter * adapter)6345597088cSDongdong Hao static void leapraid_clean_active_cmds(struct leapraid_adapter *adapter)
6355597088cSDongdong Hao {
6365597088cSDongdong Hao leapraid_clean_active_driver_cmds(adapter);
6375597088cSDongdong Hao leapraid_clean_active_fw_evt(adapter);
6385597088cSDongdong Hao leapraid_clean_active_scsi_cmds(adapter);
6395597088cSDongdong Hao }
6405597088cSDongdong Hao
leapraid_tgt_not_responding(struct leapraid_adapter * adapter,u16 hdl)6415597088cSDongdong Hao static void leapraid_tgt_not_responding(struct leapraid_adapter *adapter,
6425597088cSDongdong Hao u16 hdl)
6435597088cSDongdong Hao {
6445597088cSDongdong Hao struct leapraid_starget_priv *starget_priv = NULL;
6455597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
6465597088cSDongdong Hao unsigned long flags = 0;
6475597088cSDongdong Hao u32 adapter_state;
6485597088cSDongdong Hao
6495597088cSDongdong Hao if (adapter->access_ctrl.pcie_recovering)
6505597088cSDongdong Hao return;
6515597088cSDongdong Hao
6525597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
6535597088cSDongdong Hao if (adapter_state != LEAPRAID_DB_OPERATIONAL)
6545597088cSDongdong Hao return;
6555597088cSDongdong Hao
6565597088cSDongdong Hao if (!hdl || hdl > adapter->adapter_attr.features.max_dev_handle ||
6575597088cSDongdong Hao test_bit(hdl, adapter->dev_topo.pd_hdls))
6585597088cSDongdong Hao return;
6595597088cSDongdong Hao
6605597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
6615597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
6625597088cSDongdong Hao if (sas_dev && sas_dev->starget && sas_dev->starget->hostdata) {
6635597088cSDongdong Hao starget_priv = sas_dev->starget->hostdata;
6645597088cSDongdong Hao starget_priv->deleted = 1;
6655597088cSDongdong Hao }
6665597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
6675597088cSDongdong Hao
6685597088cSDongdong Hao if (starget_priv)
6695597088cSDongdong Hao starget_priv->hdl = LEAPRAID_INVALID_DEV_HANDLE;
6705597088cSDongdong Hao
6715597088cSDongdong Hao if (sas_dev)
6725597088cSDongdong Hao leapraid_sdev_put(sas_dev);
6735597088cSDongdong Hao }
6745597088cSDongdong Hao
leapraid_tgt_rst_send(struct leapraid_adapter * adapter,u16 hdl)6755597088cSDongdong Hao static void leapraid_tgt_rst_send(struct leapraid_adapter *adapter, u16 hdl)
6765597088cSDongdong Hao {
6775597088cSDongdong Hao struct leapraid_starget_priv *starget_priv = NULL;
6785597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
6795597088cSDongdong Hao struct leapraid_card_port *port;
6805597088cSDongdong Hao u64 sas_address;
6815597088cSDongdong Hao unsigned long flags;
6825597088cSDongdong Hao u32 adapter_state;
6835597088cSDongdong Hao
6845597088cSDongdong Hao if (adapter->access_ctrl.pcie_recovering)
6855597088cSDongdong Hao return;
6865597088cSDongdong Hao
6875597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
6885597088cSDongdong Hao if (adapter_state != LEAPRAID_DB_OPERATIONAL)
6895597088cSDongdong Hao return;
6905597088cSDongdong Hao
6915597088cSDongdong Hao if (!hdl || hdl > adapter->adapter_attr.features.max_dev_handle ||
6925597088cSDongdong Hao test_bit(hdl, adapter->dev_topo.pd_hdls))
6935597088cSDongdong Hao return;
6945597088cSDongdong Hao
6955597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
6965597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
6975597088cSDongdong Hao if (sas_dev && sas_dev->starget && sas_dev->starget->hostdata) {
6985597088cSDongdong Hao starget_priv = sas_dev->starget->hostdata;
6995597088cSDongdong Hao starget_priv->deleted = 1;
7005597088cSDongdong Hao sas_address = sas_dev->sas_addr;
7015597088cSDongdong Hao port = sas_dev->card_port;
7025597088cSDongdong Hao }
7035597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
7045597088cSDongdong Hao
7055597088cSDongdong Hao if (starget_priv) {
7065597088cSDongdong Hao leapraid_ublk_io_dev(adapter, sas_address, port);
7075597088cSDongdong Hao starget_priv->hdl = LEAPRAID_INVALID_DEV_HANDLE;
7085597088cSDongdong Hao }
7095597088cSDongdong Hao if (sas_dev)
7105597088cSDongdong Hao leapraid_sdev_put(sas_dev);
7115597088cSDongdong Hao }
7125597088cSDongdong Hao
leapraid_single_mpi_sg_append(struct leapraid_adapter * adapter,void * sge,u32 flag_and_len,dma_addr_t dma_addr)7135597088cSDongdong Hao static inline void leapraid_single_mpi_sg_append(
7145597088cSDongdong Hao struct leapraid_adapter *adapter,
7155597088cSDongdong Hao void *sge,
7165597088cSDongdong Hao u32 flag_and_len,
7175597088cSDongdong Hao dma_addr_t dma_addr)
7185597088cSDongdong Hao {
7195597088cSDongdong Hao if (adapter->adapter_attr.use_32_dma_mask) {
7205597088cSDongdong Hao struct leapraid_sge_simple32 *sge32 = sge;
7215597088cSDongdong Hao
7225597088cSDongdong Hao sge32->flg_and_len =
7235597088cSDongdong Hao cpu_to_le32(flag_and_len |
7245597088cSDongdong Hao (LEAPRAID_SGE_FLG_32 |
7255597088cSDongdong Hao LEAPRAID_SGE_FLG_SYSTEM_ADDR) <<
7265597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT);
7275597088cSDongdong Hao sge32->addr = cpu_to_le32(dma_addr);
7285597088cSDongdong Hao } else {
7295597088cSDongdong Hao struct leapraid_sge_simple64 *sge64 = sge;
7305597088cSDongdong Hao
7315597088cSDongdong Hao sge64->flg_and_len =
7325597088cSDongdong Hao cpu_to_le32(flag_and_len |
7335597088cSDongdong Hao (LEAPRAID_SGE_FLG_64 |
7345597088cSDongdong Hao LEAPRAID_SGE_FLG_SYSTEM_ADDR) <<
7355597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT);
7365597088cSDongdong Hao sge64->addr = cpu_to_le64(dma_addr);
7375597088cSDongdong Hao }
7385597088cSDongdong Hao }
7395597088cSDongdong Hao
leapraid_single_ieee_sg_append(void * sge,u8 flag,u8 next_chain_offset,u32 len,dma_addr_t dma_addr)7405597088cSDongdong Hao static inline void leapraid_single_ieee_sg_append(void *sge, u8 flag,
7415597088cSDongdong Hao u8 next_chain_offset,
7425597088cSDongdong Hao u32 len,
7435597088cSDongdong Hao dma_addr_t dma_addr)
7445597088cSDongdong Hao {
7455597088cSDongdong Hao struct leapraid_chain64_ieee_sg *ieee_sg = sge;
7465597088cSDongdong Hao
7475597088cSDongdong Hao ieee_sg->flg = flag;
7485597088cSDongdong Hao ieee_sg->next_chain_offset = next_chain_offset;
7495597088cSDongdong Hao ieee_sg->len = cpu_to_le32(len);
7505597088cSDongdong Hao ieee_sg->addr = cpu_to_le64(dma_addr);
7515597088cSDongdong Hao }
7525597088cSDongdong Hao
leapraid_build_nodata_mpi_sg(struct leapraid_adapter * adapter,void * sge)7535597088cSDongdong Hao static void leapraid_build_nodata_mpi_sg(struct leapraid_adapter *adapter,
7545597088cSDongdong Hao void *sge)
7555597088cSDongdong Hao {
7565597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
7575597088cSDongdong Hao sge,
7585597088cSDongdong Hao (LEAPRAID_SGE_FLG_LAST_ONE |
7595597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
7605597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL |
7615597088cSDongdong Hao LEAPRAID_SGE_FLG_SIMPLE_ONE) <<
7625597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT,
7635597088cSDongdong Hao LEAPRAID_SGE_NO_DATA_ADDR);
7645597088cSDongdong Hao }
7655597088cSDongdong Hao
leapraid_build_mpi_sg(struct leapraid_adapter * adapter,void * sge,dma_addr_t h2c_dma_addr,size_t h2c_size,dma_addr_t c2h_dma_addr,size_t c2h_size)7665597088cSDongdong Hao void leapraid_build_mpi_sg(struct leapraid_adapter *adapter, void *sge,
7675597088cSDongdong Hao dma_addr_t h2c_dma_addr, size_t h2c_size,
7685597088cSDongdong Hao dma_addr_t c2h_dma_addr, size_t c2h_size)
7695597088cSDongdong Hao {
7705597088cSDongdong Hao if (h2c_size && !c2h_size) {
7715597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
7725597088cSDongdong Hao sge,
7735597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
7745597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
7755597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
7765597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL |
7775597088cSDongdong Hao LEAPRAID_SGE_FLG_H2C) <<
7785597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
7795597088cSDongdong Hao h2c_size,
7805597088cSDongdong Hao h2c_dma_addr);
7815597088cSDongdong Hao } else if (!h2c_size && c2h_size) {
7825597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
7835597088cSDongdong Hao sge,
7845597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
7855597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
7865597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
7875597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL) <<
7885597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
7895597088cSDongdong Hao c2h_size,
7905597088cSDongdong Hao c2h_dma_addr);
7915597088cSDongdong Hao } else if (h2c_size && c2h_size) {
7925597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
7935597088cSDongdong Hao sge,
7945597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
7955597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
7965597088cSDongdong Hao LEAPRAID_SGE_FLG_H2C) <<
7975597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
7985597088cSDongdong Hao h2c_size,
7995597088cSDongdong Hao h2c_dma_addr);
8005597088cSDongdong Hao if (adapter->adapter_attr.use_32_dma_mask)
8015597088cSDongdong Hao sge += sizeof(struct leapraid_sge_simple32);
8025597088cSDongdong Hao else
8035597088cSDongdong Hao sge += sizeof(struct leapraid_sge_simple64);
8045597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
8055597088cSDongdong Hao sge,
8065597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
8075597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
8085597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
8095597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL) <<
8105597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
8115597088cSDongdong Hao c2h_size,
8125597088cSDongdong Hao c2h_dma_addr);
8135597088cSDongdong Hao } else {
8145597088cSDongdong Hao leapraid_build_nodata_mpi_sg(adapter, sge);
8155597088cSDongdong Hao }
8165597088cSDongdong Hao }
8175597088cSDongdong Hao
leapraid_build_ieee_nodata_sg(struct leapraid_adapter * adapter,void * sge)8185597088cSDongdong Hao void leapraid_build_ieee_nodata_sg(struct leapraid_adapter *adapter, void *sge)
8195597088cSDongdong Hao {
8205597088cSDongdong Hao leapraid_single_ieee_sg_append(sge,
8215597088cSDongdong Hao (LEAPRAID_IEEE_SGE_FLG_SIMPLE_ONE |
8225597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR |
8235597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_EOL),
8245597088cSDongdong Hao 0,
8255597088cSDongdong Hao 0,
8265597088cSDongdong Hao LEAPRAID_SGE_NO_DATA_ADDR);
8275597088cSDongdong Hao }
8285597088cSDongdong Hao
leapraid_build_scmd_ieee_sg(struct leapraid_adapter * adapter,struct scsi_cmnd * scmd,u16 taskid)8295597088cSDongdong Hao int leapraid_build_scmd_ieee_sg(struct leapraid_adapter *adapter,
8305597088cSDongdong Hao struct scsi_cmnd *scmd, u16 taskid)
8315597088cSDongdong Hao {
8325597088cSDongdong Hao struct leapraid_scsiio_req *scsiio_req;
8335597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker;
8345597088cSDongdong Hao struct scatterlist *scmd_sg_cur;
8355597088cSDongdong Hao int sg_entries_left;
8365597088cSDongdong Hao void *sg_entry_cur;
8375597088cSDongdong Hao void *host_chain;
8385597088cSDongdong Hao dma_addr_t host_chain_dma;
8395597088cSDongdong Hao u8 host_chain_cursor;
8405597088cSDongdong Hao u32 sg_entries_in_cur_seg;
8415597088cSDongdong Hao u32 chain_offset_in_cur_seg;
8425597088cSDongdong Hao u32 chain_len_in_cur_seg;
8435597088cSDongdong Hao
8445597088cSDongdong Hao io_tracker = scsi_cmd_priv(scmd);
8455597088cSDongdong Hao scsiio_req = leapraid_get_task_desc(adapter, taskid);
8465597088cSDongdong Hao scmd_sg_cur = scsi_sglist(scmd);
8475597088cSDongdong Hao sg_entries_left = scsi_dma_map(scmd);
8485597088cSDongdong Hao if (sg_entries_left < 0)
8495597088cSDongdong Hao return -ENOMEM;
8505597088cSDongdong Hao sg_entry_cur = &scsiio_req->sgl;
8515597088cSDongdong Hao if (sg_entries_left <= LEAPRAID_SGL_INLINE_THRESHOLD)
8525597088cSDongdong Hao goto fill_last_seg;
8535597088cSDongdong Hao
8545597088cSDongdong Hao scsiio_req->chain_offset = LEAPRAID_CHAIN_OFFSET_DWORDS;
8555597088cSDongdong Hao leapraid_single_ieee_sg_append(sg_entry_cur,
8565597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SIMPLE_ONE |
8575597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR,
8585597088cSDongdong Hao 0, sg_dma_len(scmd_sg_cur),
8595597088cSDongdong Hao sg_dma_address(scmd_sg_cur));
8605597088cSDongdong Hao scmd_sg_cur = sg_next(scmd_sg_cur);
8615597088cSDongdong Hao sg_entry_cur += LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
8625597088cSDongdong Hao sg_entries_left--;
8635597088cSDongdong Hao
8645597088cSDongdong Hao host_chain_cursor = 0;
8655597088cSDongdong Hao host_chain = io_tracker->chain +
8665597088cSDongdong Hao host_chain_cursor * LEAPRAID_CHAIN_SEG_SIZE;
8675597088cSDongdong Hao host_chain_dma = io_tracker->chain_dma +
8685597088cSDongdong Hao host_chain_cursor * LEAPRAID_CHAIN_SEG_SIZE;
8695597088cSDongdong Hao host_chain_cursor += 1;
8705597088cSDongdong Hao for (;;) {
8715597088cSDongdong Hao sg_entries_in_cur_seg =
8725597088cSDongdong Hao (sg_entries_left <= LEAPRAID_MAX_SGES_IN_CHAIN) ?
8735597088cSDongdong Hao sg_entries_left : LEAPRAID_MAX_SGES_IN_CHAIN;
8745597088cSDongdong Hao chain_offset_in_cur_seg =
8755597088cSDongdong Hao (sg_entries_left == (int)sg_entries_in_cur_seg) ?
8765597088cSDongdong Hao 0 : sg_entries_in_cur_seg;
8775597088cSDongdong Hao chain_len_in_cur_seg = sg_entries_in_cur_seg *
8785597088cSDongdong Hao LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
8795597088cSDongdong Hao if (chain_offset_in_cur_seg)
8805597088cSDongdong Hao chain_len_in_cur_seg += LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
8815597088cSDongdong Hao
8825597088cSDongdong Hao leapraid_single_ieee_sg_append(
8835597088cSDongdong Hao sg_entry_cur,
8845597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_CHAIN_ONE |
8855597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR,
8865597088cSDongdong Hao chain_offset_in_cur_seg, chain_len_in_cur_seg,
8875597088cSDongdong Hao host_chain_dma);
8885597088cSDongdong Hao sg_entry_cur = host_chain;
8895597088cSDongdong Hao if (!chain_offset_in_cur_seg)
8905597088cSDongdong Hao goto fill_last_seg;
8915597088cSDongdong Hao
8925597088cSDongdong Hao while (sg_entries_in_cur_seg) {
8935597088cSDongdong Hao leapraid_single_ieee_sg_append(
8945597088cSDongdong Hao sg_entry_cur,
8955597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SIMPLE_ONE |
8965597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR,
8975597088cSDongdong Hao 0, sg_dma_len(scmd_sg_cur),
8985597088cSDongdong Hao sg_dma_address(scmd_sg_cur));
8995597088cSDongdong Hao scmd_sg_cur = sg_next(scmd_sg_cur);
9005597088cSDongdong Hao sg_entry_cur += LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
9015597088cSDongdong Hao sg_entries_left--;
9025597088cSDongdong Hao sg_entries_in_cur_seg--;
9035597088cSDongdong Hao }
9045597088cSDongdong Hao host_chain = io_tracker->chain +
9055597088cSDongdong Hao host_chain_cursor * LEAPRAID_CHAIN_SEG_SIZE;
9065597088cSDongdong Hao host_chain_dma = io_tracker->chain_dma +
9075597088cSDongdong Hao host_chain_cursor * LEAPRAID_CHAIN_SEG_SIZE;
9085597088cSDongdong Hao host_chain_cursor += 1;
9095597088cSDongdong Hao }
9105597088cSDongdong Hao
9115597088cSDongdong Hao fill_last_seg:
9125597088cSDongdong Hao while (sg_entries_left > 0) {
9135597088cSDongdong Hao u32 flags = LEAPRAID_IEEE_SGE_FLG_SIMPLE_ONE |
9145597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR;
9155597088cSDongdong Hao if (sg_entries_left == 1)
9165597088cSDongdong Hao flags |= LEAPRAID_IEEE_SGE_FLG_EOL;
9175597088cSDongdong Hao leapraid_single_ieee_sg_append(sg_entry_cur, flags,
9185597088cSDongdong Hao 0, sg_dma_len(scmd_sg_cur),
9195597088cSDongdong Hao sg_dma_address(scmd_sg_cur));
9205597088cSDongdong Hao scmd_sg_cur = sg_next(scmd_sg_cur);
9215597088cSDongdong Hao sg_entry_cur += LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
9225597088cSDongdong Hao sg_entries_left--;
9235597088cSDongdong Hao }
9245597088cSDongdong Hao return 0;
9255597088cSDongdong Hao }
9265597088cSDongdong Hao
leapraid_build_ieee_sg(struct leapraid_adapter * adapter,void * sge,dma_addr_t h2c_dma_addr,size_t h2c_size,dma_addr_t c2h_dma_addr,size_t c2h_size)9275597088cSDongdong Hao void leapraid_build_ieee_sg(struct leapraid_adapter *adapter, void *sge,
9285597088cSDongdong Hao dma_addr_t h2c_dma_addr, size_t h2c_size,
9295597088cSDongdong Hao dma_addr_t c2h_dma_addr, size_t c2h_size)
9305597088cSDongdong Hao {
9315597088cSDongdong Hao u32 base_flag;
9325597088cSDongdong Hao u32 flag;
9335597088cSDongdong Hao
9345597088cSDongdong Hao base_flag = LEAPRAID_IEEE_SGE_FLG_SIMPLE_ONE |
9355597088cSDongdong Hao LEAPRAID_IEEE_SGE_FLG_SYSTEM_ADDR;
9365597088cSDongdong Hao
9375597088cSDongdong Hao if (h2c_size && !c2h_size) {
9385597088cSDongdong Hao flag = base_flag | LEAPRAID_IEEE_SGE_FLG_EOL;
9395597088cSDongdong Hao
9405597088cSDongdong Hao leapraid_single_ieee_sg_append(sge,
9415597088cSDongdong Hao flag,
9425597088cSDongdong Hao 0,
9435597088cSDongdong Hao h2c_size,
9445597088cSDongdong Hao h2c_dma_addr);
9455597088cSDongdong Hao } else if (!h2c_size && c2h_size) {
9465597088cSDongdong Hao flag = base_flag | LEAPRAID_IEEE_SGE_FLG_EOL;
9475597088cSDongdong Hao
9485597088cSDongdong Hao leapraid_single_ieee_sg_append(sge,
9495597088cSDongdong Hao flag,
9505597088cSDongdong Hao 0,
9515597088cSDongdong Hao c2h_size,
9525597088cSDongdong Hao c2h_dma_addr);
9535597088cSDongdong Hao } else if (h2c_size && c2h_size) {
9545597088cSDongdong Hao leapraid_single_ieee_sg_append(sge,
9555597088cSDongdong Hao base_flag,
9565597088cSDongdong Hao 0,
9575597088cSDongdong Hao h2c_size,
9585597088cSDongdong Hao h2c_dma_addr);
9595597088cSDongdong Hao sge += LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
9605597088cSDongdong Hao
9615597088cSDongdong Hao flag = base_flag | LEAPRAID_IEEE_SGE_FLG_EOL;
9625597088cSDongdong Hao leapraid_single_ieee_sg_append(sge,
9635597088cSDongdong Hao flag,
9645597088cSDongdong Hao 0,
9655597088cSDongdong Hao c2h_size,
9665597088cSDongdong Hao c2h_dma_addr);
9675597088cSDongdong Hao } else {
9685597088cSDongdong Hao leapraid_build_ieee_nodata_sg(adapter, sge);
9695597088cSDongdong Hao }
9705597088cSDongdong Hao }
9715597088cSDongdong Hao
leapraid_hold_lock_get_sas_dev_from_tgt(struct leapraid_adapter * adapter,struct leapraid_starget_priv * tgt_priv)9725597088cSDongdong Hao struct leapraid_sas_dev *leapraid_hold_lock_get_sas_dev_from_tgt(
9735597088cSDongdong Hao struct leapraid_adapter *adapter,
9745597088cSDongdong Hao struct leapraid_starget_priv *tgt_priv)
9755597088cSDongdong Hao {
9765597088cSDongdong Hao assert_spin_locked(&adapter->dev_topo.sas_dev_lock);
9775597088cSDongdong Hao if (tgt_priv->sas_dev)
9785597088cSDongdong Hao leapraid_sdev_get(tgt_priv->sas_dev);
9795597088cSDongdong Hao
9805597088cSDongdong Hao return tgt_priv->sas_dev;
9815597088cSDongdong Hao }
9825597088cSDongdong Hao
leapraid_get_sas_dev_from_tgt(struct leapraid_adapter * adapter,struct leapraid_starget_priv * tgt_priv)9835597088cSDongdong Hao struct leapraid_sas_dev *leapraid_get_sas_dev_from_tgt(
9845597088cSDongdong Hao struct leapraid_adapter *adapter,
9855597088cSDongdong Hao struct leapraid_starget_priv *tgt_priv)
9865597088cSDongdong Hao {
9875597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
9885597088cSDongdong Hao unsigned long flags;
9895597088cSDongdong Hao
9905597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
9915597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_from_tgt(adapter, tgt_priv);
9925597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
9935597088cSDongdong Hao return sas_dev;
9945597088cSDongdong Hao }
9955597088cSDongdong Hao
leapraid_get_port_by_id(struct leapraid_adapter * adapter,u8 port_id,bool skip_dirty)9965597088cSDongdong Hao static struct leapraid_card_port *leapraid_get_port_by_id(
9975597088cSDongdong Hao struct leapraid_adapter *adapter,
9985597088cSDongdong Hao u8 port_id, bool skip_dirty)
9995597088cSDongdong Hao {
10005597088cSDongdong Hao struct leapraid_card_port *port;
10015597088cSDongdong Hao struct leapraid_card_port *dirty_port = NULL;
10025597088cSDongdong Hao
10035597088cSDongdong Hao if (!adapter->adapter_attr.enable_mp)
10045597088cSDongdong Hao port_id = LEAPRAID_DISABLE_MP_PORT_ID;
10055597088cSDongdong Hao
10065597088cSDongdong Hao list_for_each_entry(port, &adapter->dev_topo.card_port_list, list) {
10075597088cSDongdong Hao if (port->port_id != port_id)
10085597088cSDongdong Hao continue;
10095597088cSDongdong Hao
10105597088cSDongdong Hao if (!(port->flg & LEAPRAID_CARD_PORT_FLG_DIRTY))
10115597088cSDongdong Hao return port;
10125597088cSDongdong Hao
10135597088cSDongdong Hao if (skip_dirty && !dirty_port)
10145597088cSDongdong Hao dirty_port = port;
10155597088cSDongdong Hao }
10165597088cSDongdong Hao
10175597088cSDongdong Hao if (dirty_port)
10185597088cSDongdong Hao return dirty_port;
10195597088cSDongdong Hao
10205597088cSDongdong Hao if (unlikely(!adapter->adapter_attr.enable_mp)) {
10215597088cSDongdong Hao port = kzalloc_obj(*port, GFP_ATOMIC);
10225597088cSDongdong Hao if (!port) {
10235597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
10245597088cSDongdong Hao "%s: Failed to alloc port\n", __func__);
10255597088cSDongdong Hao return NULL;
10265597088cSDongdong Hao }
10275597088cSDongdong Hao
10285597088cSDongdong Hao port->port_id = LEAPRAID_DISABLE_MP_PORT_ID;
10295597088cSDongdong Hao list_add_tail(&port->list, &adapter->dev_topo.card_port_list);
10305597088cSDongdong Hao return port;
10315597088cSDongdong Hao }
10325597088cSDongdong Hao
10335597088cSDongdong Hao return NULL;
10345597088cSDongdong Hao }
10355597088cSDongdong Hao
leapraid_get_vphy_by_phy(struct leapraid_card_port * port,u32 phy_seq_num)10365597088cSDongdong Hao struct leapraid_vphy *leapraid_get_vphy_by_phy(struct leapraid_card_port *port,
10375597088cSDongdong Hao u32 phy_seq_num)
10385597088cSDongdong Hao {
10395597088cSDongdong Hao struct leapraid_vphy *vphy;
10405597088cSDongdong Hao
10415597088cSDongdong Hao if (!port || !port->vphys_mask)
10425597088cSDongdong Hao return NULL;
10435597088cSDongdong Hao
10445597088cSDongdong Hao list_for_each_entry(vphy, &port->vphys_list, list) {
10455597088cSDongdong Hao if (vphy->phy_mask & BIT(phy_seq_num))
10465597088cSDongdong Hao return vphy;
10475597088cSDongdong Hao }
10485597088cSDongdong Hao
10495597088cSDongdong Hao return NULL;
10505597088cSDongdong Hao }
10515597088cSDongdong Hao
leapraid_hold_lock_get_sas_dev_by_addr_and_rphy(struct leapraid_adapter * adapter,u64 sas_address,struct sas_rphy * rphy)10525597088cSDongdong Hao struct leapraid_sas_dev *leapraid_hold_lock_get_sas_dev_by_addr_and_rphy(
10535597088cSDongdong Hao struct leapraid_adapter *adapter,
10545597088cSDongdong Hao u64 sas_address,
10555597088cSDongdong Hao struct sas_rphy *rphy)
10565597088cSDongdong Hao {
10575597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
10585597088cSDongdong Hao
10595597088cSDongdong Hao assert_spin_locked(&adapter->dev_topo.sas_dev_lock);
10605597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_list, list)
10615597088cSDongdong Hao if (sas_dev->sas_addr == sas_address &&
10625597088cSDongdong Hao sas_dev->rphy == rphy) {
10635597088cSDongdong Hao leapraid_sdev_get(sas_dev);
10645597088cSDongdong Hao return sas_dev;
10655597088cSDongdong Hao }
10665597088cSDongdong Hao
10675597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_init_list,
10685597088cSDongdong Hao list)
10695597088cSDongdong Hao if (sas_dev->sas_addr == sas_address &&
10705597088cSDongdong Hao sas_dev->rphy == rphy) {
10715597088cSDongdong Hao leapraid_sdev_get(sas_dev);
10725597088cSDongdong Hao return sas_dev;
10735597088cSDongdong Hao }
10745597088cSDongdong Hao
10755597088cSDongdong Hao return NULL;
10765597088cSDongdong Hao }
10775597088cSDongdong Hao
leapraid_hold_lock_get_sas_dev_by_addr(struct leapraid_adapter * adapter,u64 sas_address,struct leapraid_card_port * port)10785597088cSDongdong Hao struct leapraid_sas_dev *leapraid_hold_lock_get_sas_dev_by_addr(
10795597088cSDongdong Hao struct leapraid_adapter *adapter,
10805597088cSDongdong Hao u64 sas_address, struct leapraid_card_port *port)
10815597088cSDongdong Hao {
10825597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
10835597088cSDongdong Hao
10845597088cSDongdong Hao if (!port) {
10855597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "%s: Invalid port\n", __func__);
10865597088cSDongdong Hao return NULL;
10875597088cSDongdong Hao }
10885597088cSDongdong Hao
10895597088cSDongdong Hao assert_spin_locked(&adapter->dev_topo.sas_dev_lock);
10905597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_list, list)
10915597088cSDongdong Hao if (sas_dev->sas_addr == sas_address &&
10925597088cSDongdong Hao sas_dev->card_port == port) {
10935597088cSDongdong Hao leapraid_sdev_get(sas_dev);
10945597088cSDongdong Hao return sas_dev;
10955597088cSDongdong Hao }
10965597088cSDongdong Hao
10975597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_init_list,
10985597088cSDongdong Hao list)
10995597088cSDongdong Hao if (sas_dev->sas_addr == sas_address &&
11005597088cSDongdong Hao sas_dev->card_port == port) {
11015597088cSDongdong Hao leapraid_sdev_get(sas_dev);
11025597088cSDongdong Hao return sas_dev;
11035597088cSDongdong Hao }
11045597088cSDongdong Hao
11055597088cSDongdong Hao return NULL;
11065597088cSDongdong Hao }
11075597088cSDongdong Hao
leapraid_get_sas_dev_by_addr(struct leapraid_adapter * adapter,u64 sas_address,struct leapraid_card_port * port)11085597088cSDongdong Hao struct leapraid_sas_dev *leapraid_get_sas_dev_by_addr(
11095597088cSDongdong Hao struct leapraid_adapter *adapter,
11105597088cSDongdong Hao u64 sas_address, struct leapraid_card_port *port)
11115597088cSDongdong Hao {
11125597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
11135597088cSDongdong Hao unsigned long flags;
11145597088cSDongdong Hao
11155597088cSDongdong Hao if (!port) {
11165597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "%s: Invalid port\n", __func__);
11175597088cSDongdong Hao return NULL;
11185597088cSDongdong Hao }
11195597088cSDongdong Hao
11205597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
11215597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(adapter, sas_address,
11225597088cSDongdong Hao port);
11235597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
11245597088cSDongdong Hao return sas_dev;
11255597088cSDongdong Hao }
11265597088cSDongdong Hao
leapraid_hold_lock_get_sas_dev_by_hdl(struct leapraid_adapter * adapter,u16 hdl)11275597088cSDongdong Hao struct leapraid_sas_dev *leapraid_hold_lock_get_sas_dev_by_hdl(
11285597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
11295597088cSDongdong Hao {
11305597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
11315597088cSDongdong Hao
11325597088cSDongdong Hao assert_spin_locked(&adapter->dev_topo.sas_dev_lock);
11335597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_list, list)
11345597088cSDongdong Hao if (sas_dev->hdl == hdl) {
11355597088cSDongdong Hao leapraid_sdev_get(sas_dev);
11365597088cSDongdong Hao return sas_dev;
11375597088cSDongdong Hao }
11385597088cSDongdong Hao
11395597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_init_list,
11405597088cSDongdong Hao list)
11415597088cSDongdong Hao if (sas_dev->hdl == hdl) {
11425597088cSDongdong Hao leapraid_sdev_get(sas_dev);
11435597088cSDongdong Hao return sas_dev;
11445597088cSDongdong Hao }
11455597088cSDongdong Hao
11465597088cSDongdong Hao return NULL;
11475597088cSDongdong Hao }
11485597088cSDongdong Hao
leapraid_get_sas_dev_by_hdl(struct leapraid_adapter * adapter,u16 hdl)11495597088cSDongdong Hao struct leapraid_sas_dev *leapraid_get_sas_dev_by_hdl(
11505597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
11515597088cSDongdong Hao {
11525597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
11535597088cSDongdong Hao unsigned long flags;
11545597088cSDongdong Hao
11555597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
11565597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
11575597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
11585597088cSDongdong Hao return sas_dev;
11595597088cSDongdong Hao }
11605597088cSDongdong Hao
leapraid_sas_dev_remove(struct leapraid_adapter * adapter,struct leapraid_sas_dev * sas_dev)11615597088cSDongdong Hao void leapraid_sas_dev_remove(struct leapraid_adapter *adapter,
11625597088cSDongdong Hao struct leapraid_sas_dev *sas_dev)
11635597088cSDongdong Hao {
11645597088cSDongdong Hao unsigned long flags;
11655597088cSDongdong Hao bool del_from_list;
11665597088cSDongdong Hao
11675597088cSDongdong Hao if (!sas_dev) {
11685597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
11695597088cSDongdong Hao "%s: Invalid SAS device\n", __func__);
11705597088cSDongdong Hao return;
11715597088cSDongdong Hao }
11725597088cSDongdong Hao
11735597088cSDongdong Hao del_from_list = false;
11745597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
11755597088cSDongdong Hao if (!list_empty(&sas_dev->list)) {
11765597088cSDongdong Hao list_del_init(&sas_dev->list);
11775597088cSDongdong Hao del_from_list = true;
11785597088cSDongdong Hao }
11795597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
11805597088cSDongdong Hao
11815597088cSDongdong Hao if (del_from_list) {
11825597088cSDongdong Hao leapraid_clear_cached_boot_dev(adapter, sas_dev, 0);
11835597088cSDongdong Hao leapraid_sdev_put(sas_dev);
11845597088cSDongdong Hao }
11855597088cSDongdong Hao }
11865597088cSDongdong Hao
leapraid_sas_dev_remove_by_hdl(struct leapraid_adapter * adapter,u16 hdl)11875597088cSDongdong Hao static void leapraid_sas_dev_remove_by_hdl(struct leapraid_adapter *adapter,
11885597088cSDongdong Hao u16 hdl)
11895597088cSDongdong Hao {
11905597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
11915597088cSDongdong Hao unsigned long flags;
11925597088cSDongdong Hao bool del_from_list;
11935597088cSDongdong Hao
11945597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
11955597088cSDongdong Hao return;
11965597088cSDongdong Hao
11975597088cSDongdong Hao del_from_list = false;
11985597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
11995597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
12005597088cSDongdong Hao if (sas_dev && (!list_empty(&sas_dev->list))) {
12015597088cSDongdong Hao list_del_init(&sas_dev->list);
12025597088cSDongdong Hao del_from_list = true;
12035597088cSDongdong Hao leapraid_sdev_put(sas_dev);
12045597088cSDongdong Hao }
12055597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
12065597088cSDongdong Hao
12075597088cSDongdong Hao if (del_from_list) {
12085597088cSDongdong Hao leapraid_remove_device(adapter, sas_dev);
12095597088cSDongdong Hao leapraid_sdev_put(sas_dev);
12105597088cSDongdong Hao }
12115597088cSDongdong Hao }
12125597088cSDongdong Hao
leapraid_sas_dev_remove_by_sas_address(struct leapraid_adapter * adapter,u64 sas_address,struct leapraid_card_port * port)12135597088cSDongdong Hao void leapraid_sas_dev_remove_by_sas_address(struct leapraid_adapter *adapter,
12145597088cSDongdong Hao u64 sas_address,
12155597088cSDongdong Hao struct leapraid_card_port *port)
12165597088cSDongdong Hao {
12175597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
12185597088cSDongdong Hao unsigned long flags;
12195597088cSDongdong Hao bool del_from_list;
12205597088cSDongdong Hao
12215597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
12225597088cSDongdong Hao return;
12235597088cSDongdong Hao
12245597088cSDongdong Hao del_from_list = false;
12255597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
12265597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(adapter, sas_address,
12275597088cSDongdong Hao port);
12285597088cSDongdong Hao if (sas_dev && (!list_empty(&sas_dev->list))) {
12295597088cSDongdong Hao list_del_init(&sas_dev->list);
12305597088cSDongdong Hao del_from_list = true;
12315597088cSDongdong Hao leapraid_sdev_put(sas_dev);
12325597088cSDongdong Hao }
12335597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
12345597088cSDongdong Hao
12355597088cSDongdong Hao if (del_from_list) {
12365597088cSDongdong Hao leapraid_remove_device(adapter, sas_dev);
12375597088cSDongdong Hao leapraid_sdev_put(sas_dev);
12385597088cSDongdong Hao }
12395597088cSDongdong Hao }
12405597088cSDongdong Hao
leapraid_raid_volume_find_by_id(struct leapraid_adapter * adapter,uint id,uint channel)12415597088cSDongdong Hao struct leapraid_raid_volume *leapraid_raid_volume_find_by_id(
12425597088cSDongdong Hao struct leapraid_adapter *adapter, uint id, uint channel)
12435597088cSDongdong Hao {
12445597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
12455597088cSDongdong Hao unsigned long flags;
12465597088cSDongdong Hao
12475597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
12485597088cSDongdong Hao list_for_each_entry(raid_volume, &adapter->dev_topo.raid_volume_list,
12495597088cSDongdong Hao list) {
12505597088cSDongdong Hao if (raid_volume->id == id && raid_volume->channel == channel) {
12515597088cSDongdong Hao leapraid_raid_volume_get(raid_volume);
12525597088cSDongdong Hao spin_unlock_irqrestore(
12535597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
12545597088cSDongdong Hao return raid_volume;
12555597088cSDongdong Hao }
12565597088cSDongdong Hao }
12575597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
12585597088cSDongdong Hao
12595597088cSDongdong Hao return NULL;
12605597088cSDongdong Hao }
12615597088cSDongdong Hao
leapraid_raid_volume_find_by_hdl(struct leapraid_adapter * adapter,u16 hdl)12625597088cSDongdong Hao struct leapraid_raid_volume *leapraid_raid_volume_find_by_hdl(
12635597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
12645597088cSDongdong Hao {
12655597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
12665597088cSDongdong Hao unsigned long flags;
12675597088cSDongdong Hao
12685597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
12695597088cSDongdong Hao list_for_each_entry(raid_volume, &adapter->dev_topo.raid_volume_list,
12705597088cSDongdong Hao list) {
12715597088cSDongdong Hao if (raid_volume->hdl == hdl) {
12725597088cSDongdong Hao leapraid_raid_volume_get(raid_volume);
12735597088cSDongdong Hao spin_unlock_irqrestore(
12745597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
12755597088cSDongdong Hao return raid_volume;
12765597088cSDongdong Hao }
12775597088cSDongdong Hao }
12785597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
12795597088cSDongdong Hao
12805597088cSDongdong Hao return NULL;
12815597088cSDongdong Hao }
12825597088cSDongdong Hao
leapraid_raid_volume_find_by_wwid(struct leapraid_adapter * adapter,u64 wwid)12835597088cSDongdong Hao static struct leapraid_raid_volume *leapraid_raid_volume_find_by_wwid(
12845597088cSDongdong Hao struct leapraid_adapter *adapter, u64 wwid)
12855597088cSDongdong Hao {
12865597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
12875597088cSDongdong Hao unsigned long flags;
12885597088cSDongdong Hao
12895597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
12905597088cSDongdong Hao list_for_each_entry(raid_volume, &adapter->dev_topo.raid_volume_list,
12915597088cSDongdong Hao list) {
12925597088cSDongdong Hao if (raid_volume->wwid == wwid) {
12935597088cSDongdong Hao leapraid_raid_volume_get(raid_volume);
12945597088cSDongdong Hao spin_unlock_irqrestore(
12955597088cSDongdong Hao &adapter->dev_topo.raid_volume_lock, flags);
12965597088cSDongdong Hao return raid_volume;
12975597088cSDongdong Hao }
12985597088cSDongdong Hao }
12995597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
13005597088cSDongdong Hao
13015597088cSDongdong Hao return NULL;
13025597088cSDongdong Hao }
13035597088cSDongdong Hao
leapraid_raid_volume_add(struct leapraid_adapter * adapter,struct leapraid_raid_volume * raid_volume)13045597088cSDongdong Hao static void leapraid_raid_volume_add(struct leapraid_adapter *adapter,
13055597088cSDongdong Hao struct leapraid_raid_volume *raid_volume)
13065597088cSDongdong Hao {
13075597088cSDongdong Hao unsigned long flags;
13085597088cSDongdong Hao
13095597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
13105597088cSDongdong Hao leapraid_raid_volume_get(raid_volume);
13115597088cSDongdong Hao list_add_tail(&raid_volume->list, &adapter->dev_topo.raid_volume_list);
13125597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
13135597088cSDongdong Hao }
13145597088cSDongdong Hao
leapraid_raid_volume_remove(struct leapraid_adapter * adapter,struct leapraid_raid_volume * raid_volume)13155597088cSDongdong Hao void leapraid_raid_volume_remove(struct leapraid_adapter *adapter,
13165597088cSDongdong Hao struct leapraid_raid_volume *raid_volume)
13175597088cSDongdong Hao {
13185597088cSDongdong Hao unsigned long flags;
13195597088cSDongdong Hao bool del_from_list = false;
13205597088cSDongdong Hao
13215597088cSDongdong Hao if (!raid_volume) {
13225597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
13235597088cSDongdong Hao "%s: Invalid RAID volume\n", __func__);
13245597088cSDongdong Hao return;
13255597088cSDongdong Hao }
13265597088cSDongdong Hao
13275597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
13285597088cSDongdong Hao if (!list_empty(&raid_volume->list)) {
13295597088cSDongdong Hao list_del_init(&raid_volume->list);
13305597088cSDongdong Hao del_from_list = true;
13315597088cSDongdong Hao }
13325597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
13335597088cSDongdong Hao
13345597088cSDongdong Hao leapraid_clear_cached_boot_dev(adapter, raid_volume, RAID_CHANNEL);
13355597088cSDongdong Hao if (del_from_list)
13365597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
13375597088cSDongdong Hao }
13385597088cSDongdong Hao
leapraid_enc_find_by_hdl(struct leapraid_adapter * adapter,u16 hdl)13395597088cSDongdong Hao static struct leapraid_enc_node *leapraid_enc_find_by_hdl(
13405597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
13415597088cSDongdong Hao {
13425597088cSDongdong Hao struct leapraid_enc_node *enc_dev;
13435597088cSDongdong Hao
13445597088cSDongdong Hao list_for_each_entry(enc_dev, &adapter->dev_topo.enc_list, list)
13455597088cSDongdong Hao if (le16_to_cpu(enc_dev->pg0.enc_hdl) == hdl)
13465597088cSDongdong Hao return enc_dev;
13475597088cSDongdong Hao
13485597088cSDongdong Hao return NULL;
13495597088cSDongdong Hao }
13505597088cSDongdong Hao
leapraid_exp_find_by_sas_address(struct leapraid_adapter * adapter,u64 sas_address,struct leapraid_card_port * port)13515597088cSDongdong Hao struct leapraid_topo_node *leapraid_exp_find_by_sas_address(
13525597088cSDongdong Hao struct leapraid_adapter *adapter,
13535597088cSDongdong Hao u64 sas_address, struct leapraid_card_port *port)
13545597088cSDongdong Hao {
13555597088cSDongdong Hao struct leapraid_topo_node *sas_exp;
13565597088cSDongdong Hao
13575597088cSDongdong Hao if (!port) {
13585597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "%s: Invalid port\n", __func__);
13595597088cSDongdong Hao return NULL;
13605597088cSDongdong Hao }
13615597088cSDongdong Hao
13625597088cSDongdong Hao list_for_each_entry(sas_exp, &adapter->dev_topo.exp_list, list)
13635597088cSDongdong Hao if (sas_exp->sas_address == sas_address &&
13645597088cSDongdong Hao sas_exp->card_port == port)
13655597088cSDongdong Hao return sas_exp;
13665597088cSDongdong Hao
13675597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
13685597088cSDongdong Hao "%s: No expander found for SAS addr=0x%016llx port=%p\n",
13695597088cSDongdong Hao __func__, (unsigned long long)sas_address, port);
13705597088cSDongdong Hao return NULL;
13715597088cSDongdong Hao }
13725597088cSDongdong Hao
leapraid_scmd_find_by_tgt(struct leapraid_adapter * adapter,uint id,uint channel)13735597088cSDongdong Hao bool leapraid_scmd_find_by_tgt(struct leapraid_adapter *adapter, uint id,
13745597088cSDongdong Hao uint channel)
13755597088cSDongdong Hao {
13765597088cSDongdong Hao struct scsi_cmnd *scmd;
13775597088cSDongdong Hao int taskid;
13785597088cSDongdong Hao
13795597088cSDongdong Hao for (taskid = 1; taskid <= adapter->shost->can_queue; taskid++) {
13805597088cSDongdong Hao scmd = leapraid_get_scmd_from_taskid(adapter, taskid);
13815597088cSDongdong Hao if (!scmd)
13825597088cSDongdong Hao continue;
13835597088cSDongdong Hao
13845597088cSDongdong Hao if (scmd->device->id == id && scmd->device->channel == channel)
13855597088cSDongdong Hao return true;
13865597088cSDongdong Hao }
13875597088cSDongdong Hao
13885597088cSDongdong Hao return false;
13895597088cSDongdong Hao }
13905597088cSDongdong Hao
leapraid_scmd_find_by_lun(struct leapraid_adapter * adapter,uint id,unsigned int lun,uint channel)13915597088cSDongdong Hao bool leapraid_scmd_find_by_lun(struct leapraid_adapter *adapter, uint id,
13925597088cSDongdong Hao unsigned int lun, uint channel)
13935597088cSDongdong Hao {
13945597088cSDongdong Hao struct scsi_cmnd *scmd;
13955597088cSDongdong Hao int taskid;
13965597088cSDongdong Hao
13975597088cSDongdong Hao for (taskid = 1; taskid <= adapter->shost->can_queue; taskid++) {
13985597088cSDongdong Hao scmd = leapraid_get_scmd_from_taskid(adapter, taskid);
13995597088cSDongdong Hao if (!scmd)
14005597088cSDongdong Hao continue;
14015597088cSDongdong Hao
14025597088cSDongdong Hao if (scmd->device->id == id &&
14035597088cSDongdong Hao scmd->device->channel == channel &&
14045597088cSDongdong Hao scmd->device->lun == lun)
14055597088cSDongdong Hao return true;
14065597088cSDongdong Hao }
14075597088cSDongdong Hao
14085597088cSDongdong Hao return false;
14095597088cSDongdong Hao }
14105597088cSDongdong Hao
leapraid_exp_find_by_hdl(struct leapraid_adapter * adapter,u16 hdl)14115597088cSDongdong Hao static struct leapraid_topo_node *leapraid_exp_find_by_hdl(
14125597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
14135597088cSDongdong Hao {
14145597088cSDongdong Hao struct leapraid_topo_node *sas_exp;
14155597088cSDongdong Hao
14165597088cSDongdong Hao list_for_each_entry(sas_exp, &adapter->dev_topo.exp_list, list)
14175597088cSDongdong Hao if (sas_exp->hdl == hdl)
14185597088cSDongdong Hao return sas_exp;
14195597088cSDongdong Hao
14205597088cSDongdong Hao return NULL;
14215597088cSDongdong Hao }
14225597088cSDongdong Hao
leapraid_get_card_port_feature(struct leapraid_card_port * old_card_port,struct leapraid_card_port * card_port,struct leapraid_card_port_feature * feature)14235597088cSDongdong Hao static enum leapraid_card_port_checking_flg leapraid_get_card_port_feature(
14245597088cSDongdong Hao struct leapraid_card_port *old_card_port,
14255597088cSDongdong Hao struct leapraid_card_port *card_port,
14265597088cSDongdong Hao struct leapraid_card_port_feature *feature)
14275597088cSDongdong Hao {
14285597088cSDongdong Hao feature->dirty_flg =
14295597088cSDongdong Hao old_card_port->flg & LEAPRAID_CARD_PORT_FLG_DIRTY;
14305597088cSDongdong Hao feature->same_addr =
14315597088cSDongdong Hao old_card_port->sas_address == card_port->sas_address;
14325597088cSDongdong Hao feature->exact_phy =
14335597088cSDongdong Hao old_card_port->phy_mask == card_port->phy_mask;
14345597088cSDongdong Hao feature->phy_overlap =
14355597088cSDongdong Hao old_card_port->phy_mask & card_port->phy_mask;
14365597088cSDongdong Hao feature->same_port =
14375597088cSDongdong Hao old_card_port->port_id == card_port->port_id;
14385597088cSDongdong Hao feature->cur_chking_old_port = old_card_port;
14395597088cSDongdong Hao
14405597088cSDongdong Hao if (!feature->dirty_flg || !feature->same_addr)
14415597088cSDongdong Hao return CARD_PORT_SKIP_CHECKING;
14425597088cSDongdong Hao
14435597088cSDongdong Hao return CARD_PORT_FURTHER_CHECKING_NEEDED;
14445597088cSDongdong Hao }
14455597088cSDongdong Hao
leapraid_process_card_port_feature(struct leapraid_card_port_feature * feature)14465597088cSDongdong Hao static bool leapraid_process_card_port_feature(
14475597088cSDongdong Hao struct leapraid_card_port_feature *feature)
14485597088cSDongdong Hao {
14495597088cSDongdong Hao struct leapraid_card_port *old_card_port;
14505597088cSDongdong Hao
14515597088cSDongdong Hao old_card_port = feature->cur_chking_old_port;
14525597088cSDongdong Hao if (feature->exact_phy) {
14535597088cSDongdong Hao feature->checking_state = SAME_PORT_WITH_NOTHING_CHANGED;
14545597088cSDongdong Hao feature->expected_old_port = old_card_port;
14555597088cSDongdong Hao return true;
14565597088cSDongdong Hao }
14575597088cSDongdong Hao
14585597088cSDongdong Hao if (feature->phy_overlap) {
14595597088cSDongdong Hao if (feature->same_port) {
14605597088cSDongdong Hao feature->checking_state =
14615597088cSDongdong Hao SAME_PORT_WITH_PARTIALLY_CHANGED_PHYS;
14625597088cSDongdong Hao feature->expected_old_port = old_card_port;
14635597088cSDongdong Hao } else if (feature->checking_state !=
14645597088cSDongdong Hao SAME_PORT_WITH_PARTIALLY_CHANGED_PHYS) {
14655597088cSDongdong Hao feature->checking_state =
14665597088cSDongdong Hao SAME_ADDR_WITH_PARTIALLY_CHANGED_PHYS;
14675597088cSDongdong Hao feature->expected_old_port = old_card_port;
14685597088cSDongdong Hao }
14695597088cSDongdong Hao } else if (feature->checking_state !=
14705597088cSDongdong Hao SAME_PORT_WITH_PARTIALLY_CHANGED_PHYS &&
14715597088cSDongdong Hao feature->checking_state !=
14725597088cSDongdong Hao SAME_ADDR_WITH_PARTIALLY_CHANGED_PHYS) {
14735597088cSDongdong Hao feature->checking_state = SAME_ADDR_ONLY;
14745597088cSDongdong Hao feature->expected_old_port = old_card_port;
14755597088cSDongdong Hao feature->same_addr_port_count++;
14765597088cSDongdong Hao }
14775597088cSDongdong Hao
14785597088cSDongdong Hao return false;
14795597088cSDongdong Hao }
14805597088cSDongdong Hao
leapraid_check_card_port(struct leapraid_adapter * adapter,struct leapraid_card_port * card_port,struct leapraid_card_port ** expected_card_port,int * count)14815597088cSDongdong Hao static int leapraid_check_card_port(
14825597088cSDongdong Hao struct leapraid_adapter *adapter,
14835597088cSDongdong Hao struct leapraid_card_port *card_port,
14845597088cSDongdong Hao struct leapraid_card_port **expected_card_port,
14855597088cSDongdong Hao int *count)
14865597088cSDongdong Hao {
14875597088cSDongdong Hao struct leapraid_card_port *old_card_port;
14885597088cSDongdong Hao struct leapraid_card_port_feature feature;
14895597088cSDongdong Hao
14905597088cSDongdong Hao *expected_card_port = NULL;
14915597088cSDongdong Hao memset(&feature, 0, sizeof(struct leapraid_card_port_feature));
14925597088cSDongdong Hao feature.expected_old_port = NULL;
14935597088cSDongdong Hao feature.same_addr_port_count = 0;
14945597088cSDongdong Hao feature.checking_state = NEW_CARD_PORT;
14955597088cSDongdong Hao
14965597088cSDongdong Hao list_for_each_entry(old_card_port, &adapter->dev_topo.card_port_list,
14975597088cSDongdong Hao list) {
14985597088cSDongdong Hao if (leapraid_get_card_port_feature(old_card_port, card_port,
14995597088cSDongdong Hao &feature))
15005597088cSDongdong Hao continue;
15015597088cSDongdong Hao
15025597088cSDongdong Hao if (leapraid_process_card_port_feature(&feature))
15035597088cSDongdong Hao break;
15045597088cSDongdong Hao }
15055597088cSDongdong Hao
15065597088cSDongdong Hao if (feature.checking_state == SAME_ADDR_ONLY)
15075597088cSDongdong Hao *count = feature.same_addr_port_count;
15085597088cSDongdong Hao
15095597088cSDongdong Hao *expected_card_port = feature.expected_old_port;
15105597088cSDongdong Hao return feature.checking_state;
15115597088cSDongdong Hao }
15125597088cSDongdong Hao
leapraid_del_phy_part_of_anther_port(struct leapraid_adapter * adapter,struct leapraid_card_port * card_port_table,int index,u8 port_count,int offset)15135597088cSDongdong Hao static void leapraid_del_phy_part_of_anther_port(
15145597088cSDongdong Hao struct leapraid_adapter *adapter,
15155597088cSDongdong Hao struct leapraid_card_port *card_port_table, int index,
15165597088cSDongdong Hao u8 port_count, int offset)
15175597088cSDongdong Hao {
15185597088cSDongdong Hao struct leapraid_topo_node *card_topo_node;
15195597088cSDongdong Hao bool found = false;
15205597088cSDongdong Hao int i;
15215597088cSDongdong Hao
15225597088cSDongdong Hao card_topo_node = &adapter->dev_topo.card;
15235597088cSDongdong Hao for (i = 0; i < port_count; i++) {
15245597088cSDongdong Hao if (i == index)
15255597088cSDongdong Hao continue;
15265597088cSDongdong Hao
15275597088cSDongdong Hao if (card_port_table[i].phy_mask & BIT(offset)) {
15285597088cSDongdong Hao leapraid_transport_detach_phy_to_port(
15295597088cSDongdong Hao adapter,
15305597088cSDongdong Hao card_topo_node,
15315597088cSDongdong Hao &card_topo_node->card_phy[offset]);
15325597088cSDongdong Hao found = true;
15335597088cSDongdong Hao break;
15345597088cSDongdong Hao }
15355597088cSDongdong Hao }
15365597088cSDongdong Hao
15375597088cSDongdong Hao if (!found)
15385597088cSDongdong Hao card_port_table[index].phy_mask |= BIT(offset);
15395597088cSDongdong Hao }
15405597088cSDongdong Hao
leapraid_add_or_del_phys_from_existing_port(struct leapraid_adapter * adapter,struct leapraid_card_port * card_port,struct leapraid_card_port * card_port_table,int index,u8 port_count)15415597088cSDongdong Hao static void leapraid_add_or_del_phys_from_existing_port(
15425597088cSDongdong Hao struct leapraid_adapter *adapter,
15435597088cSDongdong Hao struct leapraid_card_port *card_port,
15445597088cSDongdong Hao struct leapraid_card_port *card_port_table,
15455597088cSDongdong Hao int index, u8 port_count)
15465597088cSDongdong Hao {
15475597088cSDongdong Hao struct leapraid_topo_node *card_topo_node;
15485597088cSDongdong Hao u32 phy_mask_diff;
15495597088cSDongdong Hao u32 offset;
15505597088cSDongdong Hao
15515597088cSDongdong Hao card_topo_node = &adapter->dev_topo.card;
15525597088cSDongdong Hao phy_mask_diff = card_port->phy_mask ^
15535597088cSDongdong Hao card_port_table[index].phy_mask;
15545597088cSDongdong Hao for (offset = 0; offset < adapter->dev_topo.card.phys_num; offset++) {
15555597088cSDongdong Hao if (!(phy_mask_diff & BIT(offset)))
15565597088cSDongdong Hao continue;
15575597088cSDongdong Hao
15585597088cSDongdong Hao if (!(card_port_table[index].phy_mask & BIT(offset))) {
15595597088cSDongdong Hao leapraid_del_phy_part_of_anther_port(adapter,
15605597088cSDongdong Hao card_port_table,
15615597088cSDongdong Hao index, port_count,
15625597088cSDongdong Hao offset);
15635597088cSDongdong Hao continue;
15645597088cSDongdong Hao }
15655597088cSDongdong Hao
15665597088cSDongdong Hao if (card_topo_node->card_phy[offset].phy_is_assigned)
15675597088cSDongdong Hao leapraid_transport_detach_phy_to_port(
15685597088cSDongdong Hao adapter,
15695597088cSDongdong Hao card_topo_node,
15705597088cSDongdong Hao &card_topo_node->card_phy[offset]);
15715597088cSDongdong Hao
15725597088cSDongdong Hao leapraid_transport_attach_phy_to_port(
15735597088cSDongdong Hao adapter,
15745597088cSDongdong Hao card_topo_node,
15755597088cSDongdong Hao &card_topo_node->card_phy[offset],
15765597088cSDongdong Hao card_port->sas_address,
15775597088cSDongdong Hao card_port);
15785597088cSDongdong Hao }
15795597088cSDongdong Hao }
15805597088cSDongdong Hao
leapraid_get_next_sas_dev_from_init_list(struct leapraid_adapter * adapter)15815597088cSDongdong Hao struct leapraid_sas_dev *leapraid_get_next_sas_dev_from_init_list(
15825597088cSDongdong Hao struct leapraid_adapter *adapter)
15835597088cSDongdong Hao {
15845597088cSDongdong Hao struct leapraid_sas_dev *sas_dev = NULL;
15855597088cSDongdong Hao unsigned long flags;
15865597088cSDongdong Hao
15875597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
15885597088cSDongdong Hao if (!list_empty(&adapter->dev_topo.sas_dev_init_list)) {
15895597088cSDongdong Hao sas_dev = list_first_entry(&adapter->dev_topo.sas_dev_init_list,
15905597088cSDongdong Hao struct leapraid_sas_dev,
15915597088cSDongdong Hao list);
15925597088cSDongdong Hao leapraid_sdev_get(sas_dev);
15935597088cSDongdong Hao }
15945597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
15955597088cSDongdong Hao return sas_dev;
15965597088cSDongdong Hao }
15975597088cSDongdong Hao
leapraid_check_boot_dev_internal(u64 sas_address,u64 dev_name,u64 enc_lid,u16 slot,struct leapraid_boot_dev * boot_dev,u8 form)15985597088cSDongdong Hao static bool leapraid_check_boot_dev_internal(u64 sas_address, u64 dev_name,
15995597088cSDongdong Hao u64 enc_lid, u16 slot,
16005597088cSDongdong Hao struct leapraid_boot_dev *boot_dev,
16015597088cSDongdong Hao u8 form)
16025597088cSDongdong Hao {
16035597088cSDongdong Hao struct leapraid_boot_dev_format_sas_wwid *wwid;
16045597088cSDongdong Hao struct leapraid_boot_dev_format_enc_slot *es;
16055597088cSDongdong Hao struct leapraid_boot_dev_format_dev_name *dn;
16065597088cSDongdong Hao void *pg_dev;
16075597088cSDongdong Hao
16085597088cSDongdong Hao if (!boot_dev)
16095597088cSDongdong Hao return false;
16105597088cSDongdong Hao
16115597088cSDongdong Hao pg_dev = boot_dev->pg_dev;
16125597088cSDongdong Hao switch (form & LEAPRAID_BOOTDEV_FORM_MASK) {
16135597088cSDongdong Hao case LEAPRAID_BOOTDEV_FORM_SAS_WWID:
16145597088cSDongdong Hao wwid = pg_dev;
16155597088cSDongdong Hao
16165597088cSDongdong Hao if (!sas_address)
16175597088cSDongdong Hao return false;
16185597088cSDongdong Hao
16195597088cSDongdong Hao return sas_address == le64_to_cpu(wwid->sas_addr);
16205597088cSDongdong Hao case LEAPRAID_BOOTDEV_FORM_ENC_SLOT:
16215597088cSDongdong Hao es = pg_dev;
16225597088cSDongdong Hao
16235597088cSDongdong Hao if (!enc_lid)
16245597088cSDongdong Hao return false;
16255597088cSDongdong Hao
16265597088cSDongdong Hao return (enc_lid == le64_to_cpu(es->enc_lid) &&
16275597088cSDongdong Hao slot == le16_to_cpu(es->slot_num));
16285597088cSDongdong Hao case LEAPRAID_BOOTDEV_FORM_DEV_NAME:
16295597088cSDongdong Hao dn = pg_dev;
16305597088cSDongdong Hao
16315597088cSDongdong Hao if (!dev_name)
16325597088cSDongdong Hao return false;
16335597088cSDongdong Hao
16345597088cSDongdong Hao return dev_name == le64_to_cpu(dn->dev_name);
16355597088cSDongdong Hao case LEAPRAID_BOOTDEV_FORM_NONE:
16365597088cSDongdong Hao default:
16375597088cSDongdong Hao return false;
16385597088cSDongdong Hao }
16395597088cSDongdong Hao }
16405597088cSDongdong Hao
leapraid_boot_dev_get(void * dev,u32 chnl)16415597088cSDongdong Hao void leapraid_boot_dev_get(void *dev, u32 chnl)
16425597088cSDongdong Hao {
16435597088cSDongdong Hao if (!dev)
16445597088cSDongdong Hao return;
16455597088cSDongdong Hao
16465597088cSDongdong Hao if (chnl == RAID_CHANNEL)
16475597088cSDongdong Hao leapraid_raid_volume_get((struct leapraid_raid_volume *)dev);
16485597088cSDongdong Hao else
16495597088cSDongdong Hao leapraid_sdev_get((struct leapraid_sas_dev *)dev);
16505597088cSDongdong Hao }
16515597088cSDongdong Hao
leapraid_boot_dev_put(void * dev,u32 chnl)16525597088cSDongdong Hao void leapraid_boot_dev_put(void *dev, u32 chnl)
16535597088cSDongdong Hao {
16545597088cSDongdong Hao if (!dev)
16555597088cSDongdong Hao return;
16565597088cSDongdong Hao
16575597088cSDongdong Hao if (chnl == RAID_CHANNEL)
16585597088cSDongdong Hao leapraid_raid_volume_put((struct leapraid_raid_volume *)dev);
16595597088cSDongdong Hao else
16605597088cSDongdong Hao leapraid_sdev_put((struct leapraid_sas_dev *)dev);
16615597088cSDongdong Hao }
16625597088cSDongdong Hao
leapraid_try_set_boot_dev(struct leapraid_boot_dev * boot_dev,u64 sas_addr,u64 dev_name,u64 enc_lid,u16 slot,void * dev,u32 chnl)16635597088cSDongdong Hao static void leapraid_try_set_boot_dev(struct leapraid_boot_dev *boot_dev,
16645597088cSDongdong Hao u64 sas_addr, u64 dev_name,
16655597088cSDongdong Hao u64 enc_lid, u16 slot,
16665597088cSDongdong Hao void *dev, u32 chnl)
16675597088cSDongdong Hao {
16685597088cSDongdong Hao bool matched = false;
16695597088cSDongdong Hao
16705597088cSDongdong Hao if (boot_dev->dev)
16715597088cSDongdong Hao return;
16725597088cSDongdong Hao
16735597088cSDongdong Hao matched = leapraid_check_boot_dev_internal(sas_addr, dev_name, enc_lid,
16745597088cSDongdong Hao slot, boot_dev,
16755597088cSDongdong Hao boot_dev->form);
16765597088cSDongdong Hao if (matched) {
16775597088cSDongdong Hao leapraid_boot_dev_get(dev, chnl);
16785597088cSDongdong Hao boot_dev->dev = dev;
16795597088cSDongdong Hao boot_dev->chnl = chnl;
16805597088cSDongdong Hao }
16815597088cSDongdong Hao }
16825597088cSDongdong Hao
leapraid_clear_boot_dev(struct leapraid_adapter * adapter,struct leapraid_boot_dev * boot_dev,void * dev,u32 chnl)16835597088cSDongdong Hao static void leapraid_clear_boot_dev(struct leapraid_adapter *adapter,
16845597088cSDongdong Hao struct leapraid_boot_dev *boot_dev,
16855597088cSDongdong Hao void *dev, u32 chnl)
16865597088cSDongdong Hao {
16875597088cSDongdong Hao void *cached_dev;
16885597088cSDongdong Hao u32 cached_chnl;
16895597088cSDongdong Hao unsigned long flags;
16905597088cSDongdong Hao
16915597088cSDongdong Hao spin_lock_irqsave(&adapter->boot_devs.lock, flags);
16925597088cSDongdong Hao if (boot_dev->dev != dev || boot_dev->chnl != chnl)
16935597088cSDongdong Hao goto out_unlock;
16945597088cSDongdong Hao
16955597088cSDongdong Hao cached_dev = boot_dev->dev;
16965597088cSDongdong Hao cached_chnl = boot_dev->chnl;
16975597088cSDongdong Hao boot_dev->dev = NULL;
16985597088cSDongdong Hao boot_dev->chnl = 0;
16995597088cSDongdong Hao spin_unlock_irqrestore(&adapter->boot_devs.lock, flags);
17005597088cSDongdong Hao leapraid_boot_dev_put(cached_dev, cached_chnl);
17015597088cSDongdong Hao return;
17025597088cSDongdong Hao
17035597088cSDongdong Hao out_unlock:
17045597088cSDongdong Hao spin_unlock_irqrestore(&adapter->boot_devs.lock, flags);
17055597088cSDongdong Hao }
17065597088cSDongdong Hao
leapraid_clear_cached_boot_dev(struct leapraid_adapter * adapter,void * dev,u32 chnl)17075597088cSDongdong Hao static void leapraid_clear_cached_boot_dev(struct leapraid_adapter *adapter,
17085597088cSDongdong Hao void *dev, u32 chnl)
17095597088cSDongdong Hao {
17105597088cSDongdong Hao leapraid_clear_boot_dev(adapter,
17115597088cSDongdong Hao &adapter->boot_devs.requested_boot_dev,
17125597088cSDongdong Hao dev, chnl);
17135597088cSDongdong Hao leapraid_clear_boot_dev(adapter,
17145597088cSDongdong Hao &adapter->boot_devs.requested_alt_boot_dev,
17155597088cSDongdong Hao dev, chnl);
17165597088cSDongdong Hao leapraid_clear_boot_dev(adapter,
17175597088cSDongdong Hao &adapter->boot_devs.current_boot_dev,
17185597088cSDongdong Hao dev, chnl);
17195597088cSDongdong Hao }
17205597088cSDongdong Hao
leapraid_check_boot_dev(struct leapraid_adapter * adapter,void * dev,u32 chnl)17215597088cSDongdong Hao static void leapraid_check_boot_dev(struct leapraid_adapter *adapter,
17225597088cSDongdong Hao void *dev, u32 chnl)
17235597088cSDongdong Hao {
17245597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
17255597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
17265597088cSDongdong Hao u64 sas_addr;
17275597088cSDongdong Hao u64 dev_name = 0;
17285597088cSDongdong Hao u64 enc_lid = 0;
17295597088cSDongdong Hao u16 slot = 0;
17305597088cSDongdong Hao
17315597088cSDongdong Hao if (!adapter->scan_dev_desc.driver_loading)
17325597088cSDongdong Hao return;
17335597088cSDongdong Hao
17345597088cSDongdong Hao switch (chnl) {
17355597088cSDongdong Hao case RAID_CHANNEL:
17365597088cSDongdong Hao raid_volume = dev;
17375597088cSDongdong Hao sas_addr = raid_volume->wwid;
17385597088cSDongdong Hao break;
17395597088cSDongdong Hao default:
17405597088cSDongdong Hao sas_dev = dev;
17415597088cSDongdong Hao sas_addr = sas_dev->sas_addr;
17425597088cSDongdong Hao dev_name = sas_dev->dev_name;
17435597088cSDongdong Hao enc_lid = sas_dev->enc_lid;
17445597088cSDongdong Hao slot = sas_dev->slot;
17455597088cSDongdong Hao break;
17465597088cSDongdong Hao }
17475597088cSDongdong Hao
17485597088cSDongdong Hao leapraid_try_set_boot_dev(&adapter->boot_devs.requested_boot_dev,
17495597088cSDongdong Hao sas_addr, dev_name, enc_lid,
17505597088cSDongdong Hao slot, dev, chnl);
17515597088cSDongdong Hao leapraid_try_set_boot_dev(&adapter->boot_devs.requested_alt_boot_dev,
17525597088cSDongdong Hao sas_addr, dev_name, enc_lid,
17535597088cSDongdong Hao slot, dev, chnl);
17545597088cSDongdong Hao leapraid_try_set_boot_dev(&adapter->boot_devs.current_boot_dev,
17555597088cSDongdong Hao sas_addr, dev_name, enc_lid,
17565597088cSDongdong Hao slot, dev, chnl);
17575597088cSDongdong Hao }
17585597088cSDongdong Hao
leapraid_func_name(u8 func)17595597088cSDongdong Hao static const char *leapraid_func_name(u8 func)
17605597088cSDongdong Hao {
17615597088cSDongdong Hao switch (func) {
17625597088cSDongdong Hao case LEAPRAID_FUNC_SCSIIO:
17635597088cSDongdong Hao return "SCSIIO";
17645597088cSDongdong Hao case LEAPRAID_FUNC_SCSI_TMF:
17655597088cSDongdong Hao return "SCSI_TMF";
17665597088cSDongdong Hao case LEAPRAID_FUNC_ADAPTER_INIT:
17675597088cSDongdong Hao return "ADAPTER_INIT";
17685597088cSDongdong Hao case LEAPRAID_FUNC_GET_ADAPTER_FEATURES:
17695597088cSDongdong Hao return "GET_ADAPTER_FEATURES";
17705597088cSDongdong Hao case LEAPRAID_FUNC_CONFIG_OP:
17715597088cSDongdong Hao return "CONFIG_OP";
17725597088cSDongdong Hao case LEAPRAID_FUNC_SCAN_DEV:
17735597088cSDongdong Hao return "SCAN_DEV";
17745597088cSDongdong Hao case LEAPRAID_FUNC_EVENT_NOTIFY:
17755597088cSDongdong Hao return "EVENT_NOTIFY";
17765597088cSDongdong Hao case LEAPRAID_FUNC_FW_DOWNLOAD:
17775597088cSDongdong Hao return "FW_DOWNLOAD";
17785597088cSDongdong Hao case LEAPRAID_FUNC_FW_UPLOAD:
17795597088cSDongdong Hao return "FW_UPLOAD";
17805597088cSDongdong Hao case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH:
17815597088cSDongdong Hao return "SCSIIO_RAID_PASSTHROUGH";
17825597088cSDongdong Hao case LEAPRAID_FUNC_SCSI_ENC_PROCESSOR:
17835597088cSDongdong Hao return "SCSI_ENC_PROCESSOR";
17845597088cSDongdong Hao case LEAPRAID_FUNC_SMP_PASSTHROUGH:
17855597088cSDongdong Hao return "SMP_PASSTHROUGH";
17865597088cSDongdong Hao case LEAPRAID_FUNC_SAS_IO_UNIT_CTRL:
17875597088cSDongdong Hao return "SAS_IO_UNIT_CTRL";
17885597088cSDongdong Hao case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH:
17895597088cSDongdong Hao return "SCSIIO_SATA_PASSTHROUGH";
17905597088cSDongdong Hao case LEAPRAID_FUNC_ADAPTER_UNIT_RESET:
17915597088cSDongdong Hao return "ADAPTER_UNIT_RESET";
17925597088cSDongdong Hao case LEAPRAID_FUNC_HANDSHAKE:
17935597088cSDongdong Hao return "HANDSHAKE";
17945597088cSDongdong Hao case LEAPRAID_FUNC_LOGBUF_INIT:
17955597088cSDongdong Hao return "LOGBUF_INIT";
17965597088cSDongdong Hao default:
17975597088cSDongdong Hao return "UNKNOWN";
17985597088cSDongdong Hao }
17995597088cSDongdong Hao }
18005597088cSDongdong Hao
leapraid_cfg_action_name(u8 action)18015597088cSDongdong Hao static const char *leapraid_cfg_action_name(u8 action)
18025597088cSDongdong Hao {
18035597088cSDongdong Hao switch (action) {
18045597088cSDongdong Hao case LEAPRAID_CFG_ACT_PAGE_HEADER:
18055597088cSDongdong Hao return "PAGE_HEADER";
18065597088cSDongdong Hao case LEAPRAID_CFG_ACT_PAGE_READ_CUR:
18075597088cSDongdong Hao return "PAGE_READ_CUR";
18085597088cSDongdong Hao case LEAPRAID_CFG_ACT_PAGE_WRITE_CUR:
18095597088cSDongdong Hao return "PAGE_WRITE_CUR";
18105597088cSDongdong Hao default:
18115597088cSDongdong Hao return "UNKNOWN";
18125597088cSDongdong Hao }
18135597088cSDongdong Hao }
18145597088cSDongdong Hao
leapraid_cfg_page_type_name(u8 page_type)18155597088cSDongdong Hao static const char *leapraid_cfg_page_type_name(u8 page_type)
18165597088cSDongdong Hao {
18175597088cSDongdong Hao switch (page_type) {
18185597088cSDongdong Hao case LEAPRAID_CFG_PT_IO_UNIT:
18195597088cSDongdong Hao return "IO_UNIT";
18205597088cSDongdong Hao case LEAPRAID_CFG_PT_ADAPTER:
18215597088cSDongdong Hao return "ADAPTER";
18225597088cSDongdong Hao case LEAPRAID_CFG_PT_BIOS:
18235597088cSDongdong Hao return "BIOS";
18245597088cSDongdong Hao case LEAPRAID_CFG_PT_RAID_VOLUME:
18255597088cSDongdong Hao return "RAID_VOLUME";
18265597088cSDongdong Hao case LEAPRAID_CFG_PT_MANUFACTURING:
18275597088cSDongdong Hao return "MANUFACTURING";
18285597088cSDongdong Hao case LEAPRAID_CFG_PT_RAID_PHYSDISK:
18295597088cSDongdong Hao return "RAID_PHYSDISK";
18305597088cSDongdong Hao case LEAPRAID_CFG_PT_EXTENDED:
18315597088cSDongdong Hao return "EXTENDED";
18325597088cSDongdong Hao default:
18335597088cSDongdong Hao return "UNKNOWN";
18345597088cSDongdong Hao }
18355597088cSDongdong Hao }
18365597088cSDongdong Hao
leapraid_cfg_ext_page_type_name(u8 ext_page_type)18375597088cSDongdong Hao static const char *leapraid_cfg_ext_page_type_name(u8 ext_page_type)
18385597088cSDongdong Hao {
18395597088cSDongdong Hao switch (ext_page_type) {
18405597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_SAS_IO_UNIT:
18415597088cSDongdong Hao return "SAS_IO_UNIT";
18425597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_SAS_EXP:
18435597088cSDongdong Hao return "SAS_EXPANDER";
18445597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_SAS_DEV:
18455597088cSDongdong Hao return "SAS_DEVICE";
18465597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_SAS_PHY:
18475597088cSDongdong Hao return "SAS_PHY";
18485597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_ENC:
18495597088cSDongdong Hao return "ENCLOSURE";
18505597088cSDongdong Hao case LEAPRAID_CFG_EXTPT_RAID_CONFIG:
18515597088cSDongdong Hao return "RAID_CONFIG";
18525597088cSDongdong Hao default:
18535597088cSDongdong Hao return "UNKNOWN";
18545597088cSDongdong Hao }
18555597088cSDongdong Hao }
18565597088cSDongdong Hao
leapraid_sep_action_name(u8 action)18575597088cSDongdong Hao static const char *leapraid_sep_action_name(u8 action)
18585597088cSDongdong Hao {
18595597088cSDongdong Hao switch (action) {
18605597088cSDongdong Hao case LEAPRAID_SEP_REQ_ACT_WRITE_STATUS:
18615597088cSDongdong Hao return "WRITE_STATUS";
18625597088cSDongdong Hao default:
18635597088cSDongdong Hao return "UNKNOWN";
18645597088cSDongdong Hao }
18655597088cSDongdong Hao }
18665597088cSDongdong Hao
leapraid_sas_op_name(u8 op)18675597088cSDongdong Hao static const char *leapraid_sas_op_name(u8 op)
18685597088cSDongdong Hao {
18695597088cSDongdong Hao switch (op) {
18705597088cSDongdong Hao case LEAPRAID_SAS_OP_PHY_LINK_RESET:
18715597088cSDongdong Hao return "PHY_LINK_RESET";
18725597088cSDongdong Hao case LEAPRAID_SAS_OP_PHY_HARD_RESET:
18735597088cSDongdong Hao return "PHY_HARD_RESET";
18745597088cSDongdong Hao case LEAPRAID_SAS_OP_SET_PARAMETER:
18755597088cSDongdong Hao return "SET_PARAMETER";
18765597088cSDongdong Hao default:
18775597088cSDongdong Hao return "UNKNOWN";
18785597088cSDongdong Hao }
18795597088cSDongdong Hao }
18805597088cSDongdong Hao
leapraid_tm_type_name(u8 task_type)18815597088cSDongdong Hao static const char *leapraid_tm_type_name(u8 task_type)
18825597088cSDongdong Hao {
18835597088cSDongdong Hao switch (task_type) {
18845597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_ABORT_TASK:
18855597088cSDongdong Hao return "ABORT_TASK";
18865597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_ABRT_TASK_SET:
18875597088cSDongdong Hao return "ABORT_TASK_SET";
18885597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_TARGET_RESET:
18895597088cSDongdong Hao return "TARGET_RESET";
18905597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_LOGICAL_UNIT_RESET:
18915597088cSDongdong Hao return "LOGICAL_UNIT_RESET";
18925597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_CLEAR_TASK_SET:
18935597088cSDongdong Hao return "CLEAR_TASK_SET";
18945597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_QUERY_TASK:
18955597088cSDongdong Hao return "QUERY_TASK";
18965597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_CLEAR_ACA:
18975597088cSDongdong Hao return "CLEAR_ACA";
18985597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_QUERY_TASK_SET:
18995597088cSDongdong Hao return "QUERY_TASK_SET";
19005597088cSDongdong Hao case LEAPRAID_TM_TASKTYPE_QUERY_ASYNC_EVENT:
19015597088cSDongdong Hao return "QUERY_ASYNC_EVENT";
19025597088cSDongdong Hao default:
19035597088cSDongdong Hao return "UNKNOWN";
19045597088cSDongdong Hao }
19055597088cSDongdong Hao }
19065597088cSDongdong Hao
leapraid_log_req_context(struct leapraid_adapter * adapter,u16 smid,const void * req_data)19075597088cSDongdong Hao void leapraid_log_req_context(struct leapraid_adapter *adapter, u16 smid,
19085597088cSDongdong Hao const void *req_data)
19095597088cSDongdong Hao {
19105597088cSDongdong Hao const struct leapraid_req *req = req_data;
19115597088cSDongdong Hao
19125597088cSDongdong Hao if (!adapter || !adapter->pdev || !req_data)
19135597088cSDongdong Hao return;
19145597088cSDongdong Hao
19155597088cSDongdong Hao switch (req->func) {
19165597088cSDongdong Hao case LEAPRAID_FUNC_CONFIG_OP: {
19175597088cSDongdong Hao const struct leapraid_cfg_req *cfg_req = req_data;
19185597088cSDongdong Hao
19195597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19205597088cSDongdong Hao "cfg-req: smid=%u func=0x%02x(%s) action=0x%02x(%s)\n",
19215597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func),
19225597088cSDongdong Hao cfg_req->action,
19235597088cSDongdong Hao leapraid_cfg_action_name(cfg_req->action));
19245597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19255597088cSDongdong Hao "cfg-req: page_type=0x%02x(%s) page_num=%u\n",
19265597088cSDongdong Hao cfg_req->header.page_type,
19275597088cSDongdong Hao leapraid_cfg_page_type_name(cfg_req->header.page_type),
19285597088cSDongdong Hao cfg_req->header.page_num);
19295597088cSDongdong Hao if (cfg_req->header.page_type == LEAPRAID_CFG_PT_EXTENDED)
19305597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19315597088cSDongdong Hao "cfg-req: ext_page_type=0x%02x(%s)\n",
19325597088cSDongdong Hao cfg_req->ext_page_type,
19335597088cSDongdong Hao leapraid_cfg_ext_page_type_name(
19345597088cSDongdong Hao cfg_req->ext_page_type));
19355597088cSDongdong Hao dev_err(&adapter->pdev->dev, "cfg-req: page_addr=0x%08x\n",
19365597088cSDongdong Hao le32_to_cpu(cfg_req->page_addr));
19375597088cSDongdong Hao break;
19385597088cSDongdong Hao }
19395597088cSDongdong Hao case LEAPRAID_FUNC_SCSI_TMF: {
19405597088cSDongdong Hao const struct leapraid_scsi_tm_req *tm_req = req_data;
19415597088cSDongdong Hao
19425597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19435597088cSDongdong Hao "scsi_tm:: smid=%u func=0x%02x(%s) task=0x%02x(%s)\n",
19445597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func),
19455597088cSDongdong Hao tm_req->task_type,
19465597088cSDongdong Hao leapraid_tm_type_name(tm_req->task_type));
19475597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19485597088cSDongdong Hao "scsi_tm:: dev_hdl=0x%04x task_mid=%u\n",
19495597088cSDongdong Hao le16_to_cpu(tm_req->dev_hdl),
19505597088cSDongdong Hao le16_to_cpu(tm_req->task_mid));
19515597088cSDongdong Hao break;
19525597088cSDongdong Hao }
19535597088cSDongdong Hao case LEAPRAID_FUNC_SCSI_ENC_PROCESSOR: {
19545597088cSDongdong Hao const struct leapraid_sep_req *sep_req = req_data;
19555597088cSDongdong Hao
19565597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19575597088cSDongdong Hao "sep: smid=%u func=0x%02x(%s) action=0x%02x(%s)\n",
19585597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func),
19595597088cSDongdong Hao sep_req->act,
19605597088cSDongdong Hao leapraid_sep_action_name(sep_req->act));
19615597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19625597088cSDongdong Hao "sep: dev_hdl=0x%04x slot=%u enc_hdl=0x%04x\n",
19635597088cSDongdong Hao le16_to_cpu(sep_req->dev_hdl),
19645597088cSDongdong Hao le16_to_cpu(sep_req->slot),
19655597088cSDongdong Hao le16_to_cpu(sep_req->enc_hdl));
19665597088cSDongdong Hao break;
19675597088cSDongdong Hao }
19685597088cSDongdong Hao case LEAPRAID_FUNC_SAS_IO_UNIT_CTRL: {
19695597088cSDongdong Hao const struct leapraid_io_unit_ctrl_req *io_req = req_data;
19705597088cSDongdong Hao
19715597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19725597088cSDongdong Hao "ctl_cmd: smid=%u func=0x%02x(%s) action=0x%02x(%s)\n",
19735597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func),
19745597088cSDongdong Hao io_req->op, leapraid_sas_op_name(io_req->op));
19755597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19765597088cSDongdong Hao "ctl_cmd: dev_hdl=0x%04x param=0x%02x\n",
19775597088cSDongdong Hao le16_to_cpu(io_req->dev_hdl),
19785597088cSDongdong Hao io_req->adapter_para);
19795597088cSDongdong Hao break;
19805597088cSDongdong Hao }
19815597088cSDongdong Hao case LEAPRAID_FUNC_SMP_PASSTHROUGH: {
19825597088cSDongdong Hao const struct leapraid_smp_passthrough_req *smp_req = req_data;
19835597088cSDongdong Hao
19845597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19855597088cSDongdong Hao "smp_cmd: smid=%u func=0x%02x(%s) action=0x%02x\n",
19865597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func),
19875597088cSDongdong Hao smp_req->passthrough_flg);
19885597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19895597088cSDongdong Hao "smp_cmd: port=%u req_len=%u\n",
19905597088cSDongdong Hao smp_req->physical_port,
19915597088cSDongdong Hao le16_to_cpu(smp_req->req_data_len));
19925597088cSDongdong Hao dev_err(&adapter->pdev->dev, "smp_cmd: sas_addr=0x%016llx\n",
19935597088cSDongdong Hao (unsigned long long)le64_to_cpu(smp_req->sas_address));
19945597088cSDongdong Hao break;
19955597088cSDongdong Hao }
19965597088cSDongdong Hao default:
19975597088cSDongdong Hao dev_err(&adapter->pdev->dev,
19985597088cSDongdong Hao "cmd: smid=%u func=0x%02x(%s)\n",
19995597088cSDongdong Hao smid, req->func, leapraid_func_name(req->func));
20005597088cSDongdong Hao break;
20015597088cSDongdong Hao }
20025597088cSDongdong Hao }
20035597088cSDongdong Hao
leapraid_build_and_fire_cfg_req(struct leapraid_adapter * adapter,struct leapraid_cfg_req * leap_mpi_cfgp_req,struct leapraid_cfg_rep * leap_mpi_cfgp_rep)20045597088cSDongdong Hao static void leapraid_build_and_fire_cfg_req(
20055597088cSDongdong Hao struct leapraid_adapter *adapter,
20065597088cSDongdong Hao struct leapraid_cfg_req *leap_mpi_cfgp_req,
20075597088cSDongdong Hao struct leapraid_cfg_rep *leap_mpi_cfgp_rep)
20085597088cSDongdong Hao {
20095597088cSDongdong Hao struct leapraid_cfg_req *local_leap_cfg_req;
20105597088cSDongdong Hao u16 smid;
20115597088cSDongdong Hao
20125597088cSDongdong Hao memset(leap_mpi_cfgp_rep, 0, sizeof(struct leapraid_cfg_rep));
20135597088cSDongdong Hao memset(&adapter->driver_cmds.cfg_op_cmd.reply, 0,
20145597088cSDongdong Hao sizeof(struct leapraid_cfg_rep));
20155597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.status = LEAPRAID_CMD_PENDING;
20165597088cSDongdong Hao smid = adapter->driver_cmds.cfg_op_cmd.inter_taskid;
20175597088cSDongdong Hao local_leap_cfg_req = leapraid_get_task_desc(adapter, smid);
20185597088cSDongdong Hao memcpy(local_leap_cfg_req, leap_mpi_cfgp_req,
20195597088cSDongdong Hao sizeof(struct leapraid_cfg_req));
20205597088cSDongdong Hao init_completion(&adapter->driver_cmds.cfg_op_cmd.done);
20215597088cSDongdong Hao leapraid_fire_task(adapter, smid);
20225597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.cfg_op_cmd.done,
20235597088cSDongdong Hao LEAPRAID_CFG_OP_TIMEOUT * HZ);
20245597088cSDongdong Hao }
20255597088cSDongdong Hao
leapraid_req_cfg_func(struct leapraid_adapter * adapter,struct leapraid_cfg_req * leap_mpi_cfgp_req,struct leapraid_cfg_rep * leap_mpi_cfgp_rep,void * target_cfg_pg,void * real_cfg_pg_addr,u16 target_real_cfg_pg_sz)20265597088cSDongdong Hao static int leapraid_req_cfg_func(struct leapraid_adapter *adapter,
20275597088cSDongdong Hao struct leapraid_cfg_req *leap_mpi_cfgp_req,
20285597088cSDongdong Hao struct leapraid_cfg_rep *leap_mpi_cfgp_rep,
20295597088cSDongdong Hao void *target_cfg_pg, void *real_cfg_pg_addr,
20305597088cSDongdong Hao u16 target_real_cfg_pg_sz)
20315597088cSDongdong Hao {
20325597088cSDongdong Hao u32 adapter_status = UINT_MAX;
20335597088cSDongdong Hao bool issue_reset = false;
20345597088cSDongdong Hao u16 smid;
20355597088cSDongdong Hao u8 retry_cnt;
20365597088cSDongdong Hao int rc;
20375597088cSDongdong Hao
20385597088cSDongdong Hao retry_cnt = 0;
20395597088cSDongdong Hao mutex_lock(&adapter->driver_cmds.cfg_op_cmd.mutex);
20405597088cSDongdong Hao smid = adapter->driver_cmds.cfg_op_cmd.inter_taskid;
20415597088cSDongdong Hao retry:
20425597088cSDongdong Hao if (retry_cnt) {
20435597088cSDongdong Hao if (retry_cnt > LEAPRAID_CFG_REQ_RETRY_TIMES) {
20445597088cSDongdong Hao rc = -EFAULT;
20455597088cSDongdong Hao goto out_cleanup;
20465597088cSDongdong Hao }
20475597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
20485597088cSDongdong Hao "cfg-req: Retry request, cnt=%u\n", retry_cnt);
20495597088cSDongdong Hao }
20505597088cSDongdong Hao
20515597088cSDongdong Hao rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
20525597088cSDongdong Hao __func__);
20535597088cSDongdong Hao if (rc) {
20545597088cSDongdong Hao dev_err(&adapter->pdev->dev,
20555597088cSDongdong Hao "cfg-req: Adapter not operational\n");
20565597088cSDongdong Hao goto out_cleanup;
20575597088cSDongdong Hao }
20585597088cSDongdong Hao
20595597088cSDongdong Hao leapraid_build_and_fire_cfg_req(adapter, leap_mpi_cfgp_req,
20605597088cSDongdong Hao leap_mpi_cfgp_rep);
20615597088cSDongdong Hao if (!(adapter->driver_cmds.cfg_op_cmd.status & LEAPRAID_CMD_DONE)) {
20625597088cSDongdong Hao retry_cnt++;
20635597088cSDongdong Hao if (adapter->driver_cmds.cfg_op_cmd.status &
20645597088cSDongdong Hao LEAPRAID_CMD_RESET) {
20655597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
20665597088cSDongdong Hao "cfg-req: CMD fail due to hard reset\n");
20675597088cSDongdong Hao goto retry;
20685597088cSDongdong Hao }
20695597088cSDongdong Hao
20705597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
20715597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) {
20725597088cSDongdong Hao dev_err(&adapter->pdev->dev,
20735597088cSDongdong Hao "cfg-req: pending in %s, status=0x%x\n",
20745597088cSDongdong Hao adapter->access_ctrl.shost_recovering ?
20755597088cSDongdong Hao "shost recovery" : "pcie recovery",
20765597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.status);
20775597088cSDongdong Hao leapraid_log_req_context(adapter, smid,
20785597088cSDongdong Hao leap_mpi_cfgp_req);
20795597088cSDongdong Hao issue_reset = false;
20805597088cSDongdong Hao rc = -EFAULT;
20815597088cSDongdong Hao } else {
20825597088cSDongdong Hao dev_err(&adapter->pdev->dev,
20835597088cSDongdong Hao "cfg-req: timeout, status=0x%x, reset\n",
20845597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.status);
20855597088cSDongdong Hao leapraid_log_req_context(adapter, smid,
20865597088cSDongdong Hao leap_mpi_cfgp_req);
20875597088cSDongdong Hao issue_reset = true;
20885597088cSDongdong Hao }
20895597088cSDongdong Hao
20905597088cSDongdong Hao goto out_cleanup;
20915597088cSDongdong Hao }
20925597088cSDongdong Hao
20935597088cSDongdong Hao if (adapter->driver_cmds.cfg_op_cmd.status &
20945597088cSDongdong Hao LEAPRAID_CMD_REPLY_VALID) {
20955597088cSDongdong Hao memcpy(leap_mpi_cfgp_rep,
20965597088cSDongdong Hao &adapter->driver_cmds.cfg_op_cmd.reply,
20975597088cSDongdong Hao sizeof(struct leapraid_cfg_rep));
20985597088cSDongdong Hao adapter_status = le16_to_cpu(
20995597088cSDongdong Hao leap_mpi_cfgp_rep->adapter_status) &
21005597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
21015597088cSDongdong Hao if (adapter_status == LEAPRAID_ADAPTER_STATUS_SUCCESS &&
21025597088cSDongdong Hao target_cfg_pg && real_cfg_pg_addr &&
21035597088cSDongdong Hao target_real_cfg_pg_sz &&
21045597088cSDongdong Hao leap_mpi_cfgp_req->action ==
21055597088cSDongdong Hao LEAPRAID_CFG_ACT_PAGE_READ_CUR)
21065597088cSDongdong Hao memcpy(target_cfg_pg, real_cfg_pg_addr,
21075597088cSDongdong Hao target_real_cfg_pg_sz);
21085597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS) {
21095597088cSDongdong Hao if (adapter_status !=
21105597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_CONFIG_INVALID_PAGE)
21115597088cSDongdong Hao dev_err(&adapter->pdev->dev,
21125597088cSDongdong Hao "cfg-rep: adapter_status=0x%x\n",
21135597088cSDongdong Hao adapter_status);
21145597088cSDongdong Hao rc = -EFAULT;
21155597088cSDongdong Hao }
21165597088cSDongdong Hao } else {
21175597088cSDongdong Hao dev_err(&adapter->pdev->dev, "cfg-rep: Reply invalid\n");
21185597088cSDongdong Hao rc = -EFAULT;
21195597088cSDongdong Hao }
21205597088cSDongdong Hao
21215597088cSDongdong Hao out_cleanup:
21225597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.status = LEAPRAID_CMD_NOT_USED;
21235597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.cfg_op_cmd.mutex);
21245597088cSDongdong Hao if (issue_reset) {
21255597088cSDongdong Hao if (adapter->scan_dev_desc.first_scan_dev_fired) {
21265597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
21275597088cSDongdong Hao "%s:%d cfg-req: Failure, issuing reset\n",
21285597088cSDongdong Hao __func__, __LINE__);
21295597088cSDongdong Hao leapraid_hard_reset_handler(adapter, FULL_RESET);
21305597088cSDongdong Hao } else {
21315597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
21325597088cSDongdong Hao "cfg-req: CMD fail in init, skip reset\n");
21335597088cSDongdong Hao }
21345597088cSDongdong Hao rc = -EFAULT;
21355597088cSDongdong Hao }
21365597088cSDongdong Hao return rc;
21375597088cSDongdong Hao }
21385597088cSDongdong Hao
leapraid_request_cfg_pg_header(struct leapraid_adapter * adapter,struct leapraid_cfg_req * leap_mpi_cfgp_req,struct leapraid_cfg_rep * leap_mpi_cfgp_rep)21395597088cSDongdong Hao static int leapraid_request_cfg_pg_header(
21405597088cSDongdong Hao struct leapraid_adapter *adapter,
21415597088cSDongdong Hao struct leapraid_cfg_req *leap_mpi_cfgp_req,
21425597088cSDongdong Hao struct leapraid_cfg_rep *leap_mpi_cfgp_rep)
21435597088cSDongdong Hao {
21445597088cSDongdong Hao return leapraid_req_cfg_func(adapter, leap_mpi_cfgp_req,
21455597088cSDongdong Hao leap_mpi_cfgp_rep, NULL, NULL, 0);
21465597088cSDongdong Hao }
21475597088cSDongdong Hao
leapraid_request_cfg_pg(struct leapraid_adapter * adapter,struct leapraid_cfg_req * leap_mpi_cfgp_req,struct leapraid_cfg_rep * leap_mpi_cfgp_rep,void * target_cfg_pg,void * real_cfg_pg_addr,u16 target_real_cfg_pg_sz)21485597088cSDongdong Hao static int leapraid_request_cfg_pg(struct leapraid_adapter *adapter,
21495597088cSDongdong Hao struct leapraid_cfg_req *leap_mpi_cfgp_req,
21505597088cSDongdong Hao struct leapraid_cfg_rep *leap_mpi_cfgp_rep,
21515597088cSDongdong Hao void *target_cfg_pg, void *real_cfg_pg_addr,
21525597088cSDongdong Hao u16 target_real_cfg_pg_sz)
21535597088cSDongdong Hao {
21545597088cSDongdong Hao return leapraid_req_cfg_func(adapter, leap_mpi_cfgp_req,
21555597088cSDongdong Hao leap_mpi_cfgp_rep, target_cfg_pg,
21565597088cSDongdong Hao real_cfg_pg_addr, target_real_cfg_pg_sz);
21575597088cSDongdong Hao }
21585597088cSDongdong Hao
leapraid_op_config_page(struct leapraid_adapter * adapter,void * target_cfg_pg,union cfg_param_1 cfgp1,union cfg_param_2 cfgp2,enum config_page_action cfg_op)21595597088cSDongdong Hao int leapraid_op_config_page(struct leapraid_adapter *adapter,
21605597088cSDongdong Hao void *target_cfg_pg, union cfg_param_1 cfgp1,
21615597088cSDongdong Hao union cfg_param_2 cfgp2,
21625597088cSDongdong Hao enum config_page_action cfg_op)
21635597088cSDongdong Hao {
21645597088cSDongdong Hao struct leapraid_cfg_req leap_mpi_cfgp_req;
21655597088cSDongdong Hao struct leapraid_cfg_rep leap_mpi_cfgp_rep;
21665597088cSDongdong Hao u16 real_cfg_pg_sz;
21675597088cSDongdong Hao void *real_cfg_pg_addr;
21685597088cSDongdong Hao dma_addr_t real_cfg_pg_dma = 0;
21695597088cSDongdong Hao u32 __page_size;
21705597088cSDongdong Hao int rc;
21715597088cSDongdong Hao
21725597088cSDongdong Hao memset(&leap_mpi_cfgp_req, 0, sizeof(struct leapraid_cfg_req));
21735597088cSDongdong Hao leap_mpi_cfgp_req.func = LEAPRAID_FUNC_CONFIG_OP;
21745597088cSDongdong Hao leap_mpi_cfgp_req.action = LEAPRAID_CFG_ACT_PAGE_HEADER;
21755597088cSDongdong Hao
21765597088cSDongdong Hao switch (cfg_op) {
21775597088cSDongdong Hao case GET_BIOS_PG3:
21785597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_BIOS;
21795597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num =
21805597088cSDongdong Hao LEAPRAID_CFG_PAGE_NUM_BIOS3;
21815597088cSDongdong Hao __page_size = sizeof(struct leapraid_bios_page3);
21825597088cSDongdong Hao break;
21835597088cSDongdong Hao case GET_BIOS_PG2:
21845597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_BIOS;
21855597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num =
21865597088cSDongdong Hao LEAPRAID_CFG_PAGE_NUM_BIOS2;
21875597088cSDongdong Hao __page_size = sizeof(struct leapraid_bios_page2);
21885597088cSDongdong Hao break;
21895597088cSDongdong Hao case GET_MANUFACTURING_PG0:
21905597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type =
21915597088cSDongdong Hao LEAPRAID_CFG_PT_MANUFACTURING;
21925597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num =
21935597088cSDongdong Hao LEAPRAID_CFG_PAGE_NUM_MANU0;
21945597088cSDongdong Hao __page_size = sizeof(struct leapraid_manufacturing_p0);
21955597088cSDongdong Hao break;
21965597088cSDongdong Hao case GET_SAS_DEVICE_PG0:
21975597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
21985597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = LEAPRAID_CFG_EXTPT_SAS_DEV;
21995597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_DEV0;
22005597088cSDongdong Hao __page_size = sizeof(struct leapraid_sas_dev_p0);
22015597088cSDongdong Hao break;
22025597088cSDongdong Hao case GET_SAS_IOUNIT_PG0:
22035597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22045597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type =
22055597088cSDongdong Hao LEAPRAID_CFG_EXTPT_SAS_IO_UNIT;
22065597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num =
22075597088cSDongdong Hao LEAPRAID_CFG_PAGE_NUM_IOUNIT0;
22085597088cSDongdong Hao __page_size = cfgp1.size;
22095597088cSDongdong Hao break;
22105597088cSDongdong Hao case GET_SAS_IOUNIT_PG1:
22115597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22125597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type =
22135597088cSDongdong Hao LEAPRAID_CFG_EXTPT_SAS_IO_UNIT;
22145597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num =
22155597088cSDongdong Hao LEAPRAID_CFG_PAGE_NUM_IOUNIT1;
22165597088cSDongdong Hao __page_size = cfgp1.size;
22175597088cSDongdong Hao break;
22185597088cSDongdong Hao case GET_SAS_EXPANDER_PG0:
22195597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22205597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = LEAPRAID_CFG_EXTPT_SAS_EXP;
22215597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_EXP0;
22225597088cSDongdong Hao __page_size = sizeof(struct leapraid_exp_p0);
22235597088cSDongdong Hao break;
22245597088cSDongdong Hao case GET_SAS_EXPANDER_PG1:
22255597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22265597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = LEAPRAID_CFG_EXTPT_SAS_EXP;
22275597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_EXP1;
22285597088cSDongdong Hao __page_size = sizeof(struct leapraid_exp_p1);
22295597088cSDongdong Hao break;
22305597088cSDongdong Hao case GET_SAS_ENCLOSURE_PG0:
22315597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22325597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = LEAPRAID_CFG_EXTPT_ENC;
22335597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_ENC0;
22345597088cSDongdong Hao __page_size = sizeof(struct leapraid_enc_p0);
22355597088cSDongdong Hao break;
22365597088cSDongdong Hao case GET_PHY_PG0:
22375597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
22385597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = LEAPRAID_CFG_EXTPT_SAS_PHY;
22395597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_PHY0;
22405597088cSDongdong Hao __page_size = sizeof(struct leapraid_sas_phy_p0);
22415597088cSDongdong Hao break;
22425597088cSDongdong Hao case GET_RAID_VOLUME_PG0:
22435597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type =
22445597088cSDongdong Hao LEAPRAID_CFG_PT_RAID_VOLUME;
22455597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_VOL0;
22465597088cSDongdong Hao __page_size = cfgp1.size;
22475597088cSDongdong Hao break;
22485597088cSDongdong Hao case GET_RAID_VOLUME_PG1:
22495597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type =
22505597088cSDongdong Hao LEAPRAID_CFG_PT_RAID_VOLUME;
22515597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_VOL1;
22525597088cSDongdong Hao __page_size = sizeof(struct leapraid_raidvol_p1);
22535597088cSDongdong Hao break;
22545597088cSDongdong Hao case GET_PHY_DISK_PG0:
22555597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type =
22565597088cSDongdong Hao LEAPRAID_CFG_PT_RAID_PHYSDISK;
22575597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_PD0;
22585597088cSDongdong Hao __page_size = sizeof(struct leapraid_raidpd_p0);
22595597088cSDongdong Hao break;
22605597088cSDongdong Hao default:
22615597088cSDongdong Hao dev_err(&adapter->pdev->dev,
22625597088cSDongdong Hao "Unsupported config page action=%d!\n", cfg_op);
22635597088cSDongdong Hao return -EINVAL;
22645597088cSDongdong Hao }
22655597088cSDongdong Hao
22665597088cSDongdong Hao leapraid_build_nodata_mpi_sg(adapter,
22675597088cSDongdong Hao &leap_mpi_cfgp_req.page_buf_sge);
22685597088cSDongdong Hao rc = leapraid_request_cfg_pg_header(adapter,
22695597088cSDongdong Hao &leap_mpi_cfgp_req,
22705597088cSDongdong Hao &leap_mpi_cfgp_rep);
22715597088cSDongdong Hao if (rc) {
22725597088cSDongdong Hao dev_err(&adapter->pdev->dev,
22735597088cSDongdong Hao "cfg-req: Header failed rc=%dn", rc);
22745597088cSDongdong Hao return rc;
22755597088cSDongdong Hao }
22765597088cSDongdong Hao
22775597088cSDongdong Hao if (cfg_op == GET_SAS_DEVICE_PG0 ||
22785597088cSDongdong Hao cfg_op == GET_SAS_EXPANDER_PG0 ||
22795597088cSDongdong Hao cfg_op == GET_SAS_ENCLOSURE_PG0 ||
22805597088cSDongdong Hao cfg_op == GET_RAID_VOLUME_PG1)
22815597088cSDongdong Hao leap_mpi_cfgp_req.page_addr = cpu_to_le32(cfgp1.form |
22825597088cSDongdong Hao cfgp2.handle);
22835597088cSDongdong Hao else if (cfg_op == GET_PHY_DISK_PG0)
22845597088cSDongdong Hao leap_mpi_cfgp_req.page_addr = cpu_to_le32(cfgp1.form |
22855597088cSDongdong Hao cfgp2.form_specific);
22865597088cSDongdong Hao else if (cfg_op == GET_RAID_VOLUME_PG0)
22875597088cSDongdong Hao leap_mpi_cfgp_req.page_addr =
22885597088cSDongdong Hao cpu_to_le32(cfgp2.handle |
22895597088cSDongdong Hao LEAPRAID_RAID_VOL_CFG_PGAD_HDL);
22905597088cSDongdong Hao else if (cfg_op == GET_SAS_EXPANDER_PG1)
22915597088cSDongdong Hao leap_mpi_cfgp_req.page_addr =
22925597088cSDongdong Hao cpu_to_le32(cfgp2.handle |
22935597088cSDongdong Hao (cfgp1.phy_number <<
22945597088cSDongdong Hao LEAPRAID_SAS_EXP_CFG_PGAD_PHYNUM_SHIFT) |
22955597088cSDongdong Hao LEAPRAID_SAS_EXP_CFG_PGAD_HDL_PHY_NUM);
22965597088cSDongdong Hao else if (cfg_op == GET_PHY_PG0)
22975597088cSDongdong Hao leap_mpi_cfgp_req.page_addr = cpu_to_le32(cfgp1.phy_number |
22985597088cSDongdong Hao LEAPRAID_SAS_PHY_CFG_PGAD_PHY_NUMBER);
22995597088cSDongdong Hao
23005597088cSDongdong Hao leap_mpi_cfgp_req.action = LEAPRAID_CFG_ACT_PAGE_READ_CUR;
23015597088cSDongdong Hao
23025597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num = leap_mpi_cfgp_rep.header.page_num;
23035597088cSDongdong Hao leap_mpi_cfgp_req.header.page_type =
23045597088cSDongdong Hao leap_mpi_cfgp_rep.header.page_type;
23055597088cSDongdong Hao leap_mpi_cfgp_req.header.page_len = leap_mpi_cfgp_rep.header.page_len;
23065597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_len = leap_mpi_cfgp_rep.ext_page_len;
23075597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type = leap_mpi_cfgp_rep.ext_page_type;
23085597088cSDongdong Hao
23095597088cSDongdong Hao real_cfg_pg_sz = (leap_mpi_cfgp_req.header.page_len) ?
23105597088cSDongdong Hao leap_mpi_cfgp_req.header.page_len * sizeof(u32) :
23115597088cSDongdong Hao le16_to_cpu(leap_mpi_cfgp_rep.ext_page_len) * sizeof(u32);
23125597088cSDongdong Hao real_cfg_pg_addr = dma_alloc_coherent(&adapter->pdev->dev,
23135597088cSDongdong Hao real_cfg_pg_sz,
23145597088cSDongdong Hao &real_cfg_pg_dma,
23155597088cSDongdong Hao GFP_KERNEL);
23165597088cSDongdong Hao if (!real_cfg_pg_addr)
23175597088cSDongdong Hao return -ENOMEM;
23185597088cSDongdong Hao
23195597088cSDongdong Hao if (leap_mpi_cfgp_req.action == LEAPRAID_CFG_ACT_PAGE_WRITE_CUR) {
23205597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
23215597088cSDongdong Hao &leap_mpi_cfgp_req.page_buf_sge,
23225597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
23235597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
23245597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
23255597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL |
23265597088cSDongdong Hao LEAPRAID_SGE_FLG_H2C) <<
23275597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
23285597088cSDongdong Hao real_cfg_pg_sz,
23295597088cSDongdong Hao real_cfg_pg_dma);
23305597088cSDongdong Hao memcpy(real_cfg_pg_addr, target_cfg_pg,
23315597088cSDongdong Hao min_t(u16, real_cfg_pg_sz, __page_size));
23325597088cSDongdong Hao } else {
23335597088cSDongdong Hao memset(target_cfg_pg, 0, __page_size);
23345597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
23355597088cSDongdong Hao &leap_mpi_cfgp_req.page_buf_sge,
23365597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
23375597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
23385597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
23395597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL) <<
23405597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
23415597088cSDongdong Hao real_cfg_pg_sz,
23425597088cSDongdong Hao real_cfg_pg_dma);
23435597088cSDongdong Hao memset(real_cfg_pg_addr, 0,
23445597088cSDongdong Hao min_t(u16, real_cfg_pg_sz, __page_size));
23455597088cSDongdong Hao }
23465597088cSDongdong Hao
23475597088cSDongdong Hao rc = leapraid_request_cfg_pg(adapter,
23485597088cSDongdong Hao &leap_mpi_cfgp_req,
23495597088cSDongdong Hao &leap_mpi_cfgp_rep,
23505597088cSDongdong Hao target_cfg_pg,
23515597088cSDongdong Hao real_cfg_pg_addr,
23525597088cSDongdong Hao min_t(u16, real_cfg_pg_sz, __page_size));
23535597088cSDongdong Hao if (rc) {
23545597088cSDongdong Hao u32 status;
23555597088cSDongdong Hao
23565597088cSDongdong Hao status = le16_to_cpu(leap_mpi_cfgp_rep.adapter_status) &
23575597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
23585597088cSDongdong Hao if (status != LEAPRAID_ADAPTER_STATUS_CONFIG_INVALID_PAGE)
23595597088cSDongdong Hao dev_err(&adapter->pdev->dev,
23605597088cSDongdong Hao "cfg-req: rc=%d, pg_info: 0x%x, 0x%x, %d\n",
23615597088cSDongdong Hao rc, leap_mpi_cfgp_req.header.page_type,
23625597088cSDongdong Hao leap_mpi_cfgp_req.ext_page_type,
23635597088cSDongdong Hao leap_mpi_cfgp_req.header.page_num);
23645597088cSDongdong Hao }
23655597088cSDongdong Hao
23665597088cSDongdong Hao if (real_cfg_pg_addr)
23675597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev,
23685597088cSDongdong Hao real_cfg_pg_sz,
23695597088cSDongdong Hao real_cfg_pg_addr,
23705597088cSDongdong Hao real_cfg_pg_dma);
23715597088cSDongdong Hao
23725597088cSDongdong Hao return rc;
23735597088cSDongdong Hao }
23745597088cSDongdong Hao
leapraid_cfg_find_vol_in_page(struct leapraid_raid_cfg_p0 * raid_cfg_p0,u16 pd_hdl,u16 * vol_hdl)23755597088cSDongdong Hao static int leapraid_cfg_find_vol_in_page(
23765597088cSDongdong Hao struct leapraid_raid_cfg_p0 *raid_cfg_p0,
23775597088cSDongdong Hao u16 pd_hdl, u16 *vol_hdl)
23785597088cSDongdong Hao {
23795597088cSDongdong Hao u16 elements = raid_cfg_p0->elements_num;
23805597088cSDongdong Hao int i;
23815597088cSDongdong Hao
23825597088cSDongdong Hao for (i = 0; i < elements; i++) {
23835597088cSDongdong Hao struct leapraid_raid_cfg_p0_element *elem;
23845597088cSDongdong Hao u16 type;
23855597088cSDongdong Hao
23865597088cSDongdong Hao elem = &raid_cfg_p0->cfg_element[i];
23875597088cSDongdong Hao
23885597088cSDongdong Hao type = le16_to_cpu(elem->element_flg) &
23895597088cSDongdong Hao LEAPRAID_RAIDCFG_P0_EFLG_MASK_ELEMENT_TYPE;
23905597088cSDongdong Hao
23915597088cSDongdong Hao switch (type) {
23925597088cSDongdong Hao case LEAPRAID_RAIDCFG_P0_EFLG_VOL_PHYS_DISK_ELEMENT:
23935597088cSDongdong Hao case LEAPRAID_RAIDCFG_P0_EFLG_OCE_ELEMENT: {
23945597088cSDongdong Hao u16 phys_hdl;
23955597088cSDongdong Hao
23965597088cSDongdong Hao phys_hdl = le16_to_cpu(elem->phys_disk_dev_hdl);
23975597088cSDongdong Hao if (phys_hdl == pd_hdl) {
23985597088cSDongdong Hao *vol_hdl = le16_to_cpu(elem->vol_dev_hdl);
23995597088cSDongdong Hao return 0;
24005597088cSDongdong Hao }
24015597088cSDongdong Hao break;
24025597088cSDongdong Hao }
24035597088cSDongdong Hao case LEAPRAID_RAIDCFG_P0_EFLG_HOT_SPARE_ELEMENT:
24045597088cSDongdong Hao *vol_hdl = 0;
24055597088cSDongdong Hao return 0;
24065597088cSDongdong Hao
24075597088cSDongdong Hao default:
24085597088cSDongdong Hao break;
24095597088cSDongdong Hao }
24105597088cSDongdong Hao }
24115597088cSDongdong Hao
24125597088cSDongdong Hao return -ENOENT;
24135597088cSDongdong Hao }
24145597088cSDongdong Hao
leapraid_cfg_get_volume_hdl_dispatch(struct leapraid_adapter * adapter,struct leapraid_cfg_req * cfg_req,struct leapraid_cfg_rep * cfg_rep,struct leapraid_raid_cfg_p0 * raid_cfg_p0,void * real_cfg_pg_addr,u16 real_cfg_pg_sz,u16 raid_cfg_p0_sz,u16 pd_hdl,u16 * vol_hdl)24155597088cSDongdong Hao static int leapraid_cfg_get_volume_hdl_dispatch(
24165597088cSDongdong Hao struct leapraid_adapter *adapter,
24175597088cSDongdong Hao struct leapraid_cfg_req *cfg_req,
24185597088cSDongdong Hao struct leapraid_cfg_rep *cfg_rep,
24195597088cSDongdong Hao struct leapraid_raid_cfg_p0 *raid_cfg_p0,
24205597088cSDongdong Hao void *real_cfg_pg_addr,
24215597088cSDongdong Hao u16 real_cfg_pg_sz,
24225597088cSDongdong Hao u16 raid_cfg_p0_sz,
24235597088cSDongdong Hao u16 pd_hdl, u16 *vol_hdl)
24245597088cSDongdong Hao {
24255597088cSDongdong Hao u16 adapter_status;
24265597088cSDongdong Hao int config_num;
24275597088cSDongdong Hao int rc;
24285597088cSDongdong Hao
24295597088cSDongdong Hao config_num = 0xFF;
24305597088cSDongdong Hao while (true) {
24315597088cSDongdong Hao cfg_req->page_addr =
24325597088cSDongdong Hao cpu_to_le32(config_num +
24335597088cSDongdong Hao LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP);
24345597088cSDongdong Hao rc = leapraid_request_cfg_pg(
24355597088cSDongdong Hao adapter, cfg_req, cfg_rep,
24365597088cSDongdong Hao raid_cfg_p0, real_cfg_pg_addr,
24375597088cSDongdong Hao min_t(u16, real_cfg_pg_sz, raid_cfg_p0_sz));
24385597088cSDongdong Hao adapter_status = le16_to_cpu(cfg_rep->adapter_status) &
24395597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
24405597088cSDongdong Hao if (rc) {
24415597088cSDongdong Hao if (adapter_status ==
24425597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_CONFIG_INVALID_PAGE) {
24435597088cSDongdong Hao *vol_hdl = 0;
24445597088cSDongdong Hao return 0;
24455597088cSDongdong Hao }
24465597088cSDongdong Hao return rc;
24475597088cSDongdong Hao }
24485597088cSDongdong Hao
24495597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS)
24505597088cSDongdong Hao return LEAPRAID_OPERATION_FAILED;
24515597088cSDongdong Hao
24525597088cSDongdong Hao rc = leapraid_cfg_find_vol_in_page(raid_cfg_p0,
24535597088cSDongdong Hao pd_hdl,
24545597088cSDongdong Hao vol_hdl);
24555597088cSDongdong Hao if (rc != -ENOENT)
24565597088cSDongdong Hao return rc;
24575597088cSDongdong Hao
24585597088cSDongdong Hao config_num = raid_cfg_p0->cfg_num;
24595597088cSDongdong Hao }
24605597088cSDongdong Hao return 0;
24615597088cSDongdong Hao }
24625597088cSDongdong Hao
leapraid_cfg_get_volume_hdl(struct leapraid_adapter * adapter,u16 pd_hdl,u16 * vol_hdl)24635597088cSDongdong Hao int leapraid_cfg_get_volume_hdl(struct leapraid_adapter *adapter,
24645597088cSDongdong Hao u16 pd_hdl, u16 *vol_hdl)
24655597088cSDongdong Hao {
24665597088cSDongdong Hao struct leapraid_raid_cfg_p0 *raid_cfg_p0;
24675597088cSDongdong Hao struct leapraid_cfg_req cfg_req;
24685597088cSDongdong Hao struct leapraid_cfg_rep cfg_rep;
24695597088cSDongdong Hao dma_addr_t real_cfg_pg_dma = 0;
24705597088cSDongdong Hao void *real_cfg_pg_addr;
24715597088cSDongdong Hao u16 real_cfg_pg_sz;
24725597088cSDongdong Hao int rc, raid_cfg_p0_sz;
24735597088cSDongdong Hao
24745597088cSDongdong Hao *vol_hdl = 0;
24755597088cSDongdong Hao memset(&cfg_req, 0, sizeof(struct leapraid_cfg_req));
24765597088cSDongdong Hao cfg_req.func = LEAPRAID_FUNC_CONFIG_OP;
24775597088cSDongdong Hao cfg_req.action = LEAPRAID_CFG_ACT_PAGE_HEADER;
24785597088cSDongdong Hao cfg_req.header.page_type = LEAPRAID_CFG_PT_EXTENDED;
24795597088cSDongdong Hao cfg_req.ext_page_type = LEAPRAID_CFG_EXTPT_RAID_CONFIG;
24805597088cSDongdong Hao cfg_req.header.page_num = LEAPRAID_CFG_PAGE_NUM_VOL0;
24815597088cSDongdong Hao
24825597088cSDongdong Hao leapraid_build_nodata_mpi_sg(adapter, &cfg_req.page_buf_sge);
24835597088cSDongdong Hao rc = leapraid_request_cfg_pg_header(adapter, &cfg_req, &cfg_rep);
24845597088cSDongdong Hao if (rc)
24855597088cSDongdong Hao return rc;
24865597088cSDongdong Hao
24875597088cSDongdong Hao cfg_req.action = LEAPRAID_CFG_ACT_PAGE_READ_CUR;
24885597088cSDongdong Hao raid_cfg_p0_sz = le16_to_cpu(cfg_rep.ext_page_len) *
24895597088cSDongdong Hao LEAPRAID_CFG_UNIT_SIZE;
24905597088cSDongdong Hao raid_cfg_p0 = kmalloc(raid_cfg_p0_sz, GFP_KERNEL);
24915597088cSDongdong Hao if (!raid_cfg_p0)
24925597088cSDongdong Hao return -ENOMEM;
24935597088cSDongdong Hao
24945597088cSDongdong Hao real_cfg_pg_sz = (cfg_req.header.page_len) ?
24955597088cSDongdong Hao cfg_req.header.page_len * LEAPRAID_CFG_UNIT_SIZE :
24965597088cSDongdong Hao le16_to_cpu(cfg_rep.ext_page_len) * LEAPRAID_CFG_UNIT_SIZE;
24975597088cSDongdong Hao
24985597088cSDongdong Hao real_cfg_pg_addr = dma_alloc_coherent(&adapter->pdev->dev,
24995597088cSDongdong Hao real_cfg_pg_sz, &real_cfg_pg_dma,
25005597088cSDongdong Hao GFP_KERNEL);
25015597088cSDongdong Hao if (!real_cfg_pg_addr) {
25025597088cSDongdong Hao rc = -ENOMEM;
25035597088cSDongdong Hao goto out_free;
25045597088cSDongdong Hao }
25055597088cSDongdong Hao
25065597088cSDongdong Hao memset(raid_cfg_p0, 0, raid_cfg_p0_sz);
25075597088cSDongdong Hao leapraid_single_mpi_sg_append(adapter,
25085597088cSDongdong Hao &cfg_req.page_buf_sge,
25095597088cSDongdong Hao ((LEAPRAID_SGE_FLG_SIMPLE_ONE |
25105597088cSDongdong Hao LEAPRAID_SGE_FLG_LAST_ONE |
25115597088cSDongdong Hao LEAPRAID_SGE_FLG_EOB |
25125597088cSDongdong Hao LEAPRAID_SGE_FLG_EOL) <<
25135597088cSDongdong Hao LEAPRAID_SGE_FLG_SHIFT) |
25145597088cSDongdong Hao real_cfg_pg_sz,
25155597088cSDongdong Hao real_cfg_pg_dma);
25165597088cSDongdong Hao memset(real_cfg_pg_addr, 0,
25175597088cSDongdong Hao min_t(u16, real_cfg_pg_sz, raid_cfg_p0_sz));
25185597088cSDongdong Hao
25195597088cSDongdong Hao rc = leapraid_cfg_get_volume_hdl_dispatch(adapter,
25205597088cSDongdong Hao &cfg_req, &cfg_rep,
25215597088cSDongdong Hao raid_cfg_p0,
25225597088cSDongdong Hao real_cfg_pg_addr,
25235597088cSDongdong Hao real_cfg_pg_sz,
25245597088cSDongdong Hao raid_cfg_p0_sz,
25255597088cSDongdong Hao pd_hdl, vol_hdl);
25265597088cSDongdong Hao
25275597088cSDongdong Hao out_free:
25285597088cSDongdong Hao if (real_cfg_pg_addr)
25295597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev,
25305597088cSDongdong Hao real_cfg_pg_sz, real_cfg_pg_addr,
25315597088cSDongdong Hao real_cfg_pg_dma);
25325597088cSDongdong Hao kfree(raid_cfg_p0);
25335597088cSDongdong Hao return rc;
25345597088cSDongdong Hao }
25355597088cSDongdong Hao
leapraid_get_adapter_phys(struct leapraid_adapter * adapter,u8 * nr_phys)25365597088cSDongdong Hao static int leapraid_get_adapter_phys(struct leapraid_adapter *adapter,
25375597088cSDongdong Hao u8 *nr_phys)
25385597088cSDongdong Hao {
25395597088cSDongdong Hao struct leapraid_sas_io_unit_p0 sas_io_unit_page0;
25405597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
25415597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
25425597088cSDongdong Hao int rc;
25435597088cSDongdong Hao
25445597088cSDongdong Hao *nr_phys = 0;
25455597088cSDongdong Hao cfgp1.size = sizeof(struct leapraid_sas_io_unit_p0);
25465597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &sas_io_unit_page0, cfgp1,
25475597088cSDongdong Hao cfgp2, GET_SAS_IOUNIT_PG0);
25485597088cSDongdong Hao if (rc)
25495597088cSDongdong Hao return rc;
25505597088cSDongdong Hao
25515597088cSDongdong Hao *nr_phys = sas_io_unit_page0.phy_num;
25525597088cSDongdong Hao
25535597088cSDongdong Hao return 0;
25545597088cSDongdong Hao }
25555597088cSDongdong Hao
leapraid_cfg_get_number_pds(struct leapraid_adapter * adapter,u16 hdl,u8 * num_pds)25565597088cSDongdong Hao static int leapraid_cfg_get_number_pds(struct leapraid_adapter *adapter,
25575597088cSDongdong Hao u16 hdl, u8 *num_pds)
25585597088cSDongdong Hao {
25595597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
25605597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
25615597088cSDongdong Hao struct leapraid_raidvol_p0 raidvol_p0;
25625597088cSDongdong Hao int rc;
25635597088cSDongdong Hao
25645597088cSDongdong Hao *num_pds = 0;
25655597088cSDongdong Hao cfgp1.size = sizeof(struct leapraid_raidvol_p0);
25665597088cSDongdong Hao cfgp2.handle = hdl;
25675597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &raidvol_p0, cfgp1,
25685597088cSDongdong Hao cfgp2, GET_RAID_VOLUME_PG0);
25695597088cSDongdong Hao if (!rc)
25705597088cSDongdong Hao *num_pds = raidvol_p0.num_phys_disks;
25715597088cSDongdong Hao
25725597088cSDongdong Hao return rc;
25735597088cSDongdong Hao }
25745597088cSDongdong Hao
leapraid_cfg_get_volume_wwid(struct leapraid_adapter * adapter,u16 vol_hdl,u64 * wwid)25755597088cSDongdong Hao int leapraid_cfg_get_volume_wwid(struct leapraid_adapter *adapter,
25765597088cSDongdong Hao u16 vol_hdl, u64 *wwid)
25775597088cSDongdong Hao {
25785597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
25795597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
25805597088cSDongdong Hao struct leapraid_raidvol_p1 raidvol_p1;
25815597088cSDongdong Hao int rc;
25825597088cSDongdong Hao
25835597088cSDongdong Hao *wwid = 0;
25845597088cSDongdong Hao cfgp1.form = LEAPRAID_RAID_VOL_CFG_PGAD_HDL;
25855597088cSDongdong Hao cfgp2.handle = vol_hdl;
25865597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &raidvol_p1, cfgp1,
25875597088cSDongdong Hao cfgp2, GET_RAID_VOLUME_PG1);
25885597088cSDongdong Hao if (!rc)
25895597088cSDongdong Hao *wwid = le64_to_cpu(raidvol_p1.wwid);
25905597088cSDongdong Hao
25915597088cSDongdong Hao return rc;
25925597088cSDongdong Hao }
25935597088cSDongdong Hao
leapraid_get_sas_io_unit_page0(struct leapraid_adapter * adapter,struct leapraid_sas_io_unit_p0 * sas_io_unit_p0,u16 sas_iou_pg0_sz)25945597088cSDongdong Hao static int leapraid_get_sas_io_unit_page0(
25955597088cSDongdong Hao struct leapraid_adapter *adapter,
25965597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_io_unit_p0,
25975597088cSDongdong Hao u16 sas_iou_pg0_sz)
25985597088cSDongdong Hao {
25995597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
26005597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
26015597088cSDongdong Hao
26025597088cSDongdong Hao cfgp1.size = sas_iou_pg0_sz;
26035597088cSDongdong Hao return leapraid_op_config_page(adapter, sas_io_unit_p0, cfgp1,
26045597088cSDongdong Hao cfgp2, GET_SAS_IOUNIT_PG0);
26055597088cSDongdong Hao }
26065597088cSDongdong Hao
leapraid_get_sas_address(struct leapraid_adapter * adapter,u16 hdl,u64 * sas_address)26075597088cSDongdong Hao static int leapraid_get_sas_address(struct leapraid_adapter *adapter,
26085597088cSDongdong Hao u16 hdl, u64 *sas_address)
26095597088cSDongdong Hao {
26105597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
26115597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
26125597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
26135597088cSDongdong Hao
26145597088cSDongdong Hao *sas_address = 0;
26155597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
26165597088cSDongdong Hao cfgp2.handle = hdl;
26175597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_p0, cfgp1,
26185597088cSDongdong Hao cfgp2, GET_SAS_DEVICE_PG0))
26195597088cSDongdong Hao return -ENXIO;
26205597088cSDongdong Hao
26215597088cSDongdong Hao if (hdl <= adapter->dev_topo.card.phys_num &&
26225597088cSDongdong Hao (!(le32_to_cpu(sas_dev_p0.dev_info) & LEAPRAID_DEVTYP_SEP)))
26235597088cSDongdong Hao *sas_address = adapter->dev_topo.card.sas_address;
26245597088cSDongdong Hao else
26255597088cSDongdong Hao *sas_address = le64_to_cpu(sas_dev_p0.sas_address);
26265597088cSDongdong Hao
26275597088cSDongdong Hao return 0;
26285597088cSDongdong Hao }
26295597088cSDongdong Hao
leapraid_get_volume_cap(struct leapraid_adapter * adapter,struct leapraid_raid_volume * raid_volume)26305597088cSDongdong Hao int leapraid_get_volume_cap(struct leapraid_adapter *adapter,
26315597088cSDongdong Hao struct leapraid_raid_volume *raid_volume)
26325597088cSDongdong Hao {
26335597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
26345597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
26355597088cSDongdong Hao struct leapraid_raidvol_p0 *raidvol_p0;
26365597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
26375597088cSDongdong Hao struct leapraid_raidpd_p0 raidpd_p0;
26385597088cSDongdong Hao u8 num_pds;
26395597088cSDongdong Hao u16 sz;
26405597088cSDongdong Hao int rc = 0;
26415597088cSDongdong Hao
26425597088cSDongdong Hao if (leapraid_cfg_get_number_pds(adapter, raid_volume->hdl,
26435597088cSDongdong Hao &num_pds) || !num_pds)
26445597088cSDongdong Hao return -EFAULT;
26455597088cSDongdong Hao
26465597088cSDongdong Hao raid_volume->pd_num = num_pds;
26475597088cSDongdong Hao sz = offsetof(struct leapraid_raidvol_p0, phys_disk) +
26485597088cSDongdong Hao (num_pds * sizeof(struct leapraid_raidvol0_phys_disk));
26495597088cSDongdong Hao raidvol_p0 = kzalloc(sz, GFP_KERNEL);
26505597088cSDongdong Hao if (!raidvol_p0)
26515597088cSDongdong Hao return -ENOMEM;
26525597088cSDongdong Hao
26535597088cSDongdong Hao cfgp1.size = sz;
26545597088cSDongdong Hao cfgp2.handle = raid_volume->hdl;
26555597088cSDongdong Hao if (leapraid_op_config_page(adapter, raidvol_p0, cfgp1, cfgp2,
26565597088cSDongdong Hao GET_RAID_VOLUME_PG0)) {
26575597088cSDongdong Hao rc = -EFAULT;
26585597088cSDongdong Hao goto out_cleanup;
26595597088cSDongdong Hao }
26605597088cSDongdong Hao
26615597088cSDongdong Hao raid_volume->vol_type = raidvol_p0->volume_type;
26625597088cSDongdong Hao cfgp1.form = LEAPRAID_PHYSDISK_CFG_PGAD_PHYSDISKNUM;
26635597088cSDongdong Hao cfgp2.form_specific = raidvol_p0->phys_disk[0].phys_disk_num;
26645597088cSDongdong Hao if (!(leapraid_op_config_page(adapter, &raidpd_p0, cfgp1, cfgp2,
26655597088cSDongdong Hao GET_PHY_DISK_PG0))) {
26665597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
26675597088cSDongdong Hao cfgp2.handle = le16_to_cpu(raidpd_p0.dev_hdl);
26685597088cSDongdong Hao if (!(leapraid_op_config_page(adapter, &sas_dev_p0, cfgp1,
26695597088cSDongdong Hao cfgp2, GET_SAS_DEVICE_PG0)))
26705597088cSDongdong Hao raid_volume->dev_info =
26715597088cSDongdong Hao le32_to_cpu(sas_dev_p0.dev_info);
26725597088cSDongdong Hao }
26735597088cSDongdong Hao
26745597088cSDongdong Hao out_cleanup:
26755597088cSDongdong Hao kfree(raidvol_p0);
26765597088cSDongdong Hao return rc;
26775597088cSDongdong Hao }
26785597088cSDongdong Hao
leapraid_should_skip_poll_work(struct leapraid_adapter * adapter)26795597088cSDongdong Hao static bool leapraid_should_skip_poll_work(struct leapraid_adapter *adapter)
26805597088cSDongdong Hao {
26815597088cSDongdong Hao unsigned long flags;
26825597088cSDongdong Hao bool skip;
26835597088cSDongdong Hao
26845597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
26855597088cSDongdong Hao skip = adapter->access_ctrl.shost_recovering ||
26865597088cSDongdong Hao adapter->access_ctrl.pcie_recovering ||
26875597088cSDongdong Hao adapter->access_ctrl.host_removing;
26885597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
26895597088cSDongdong Hao
26905597088cSDongdong Hao return skip;
26915597088cSDongdong Hao }
26925597088cSDongdong Hao
leapraid_fw_log_work(struct work_struct * work)26935597088cSDongdong Hao static void leapraid_fw_log_work(struct work_struct *work)
26945597088cSDongdong Hao {
26955597088cSDongdong Hao struct leapraid_adapter *adapter = container_of(work,
26965597088cSDongdong Hao struct leapraid_adapter, fw_log_desc.fw_log_work.work);
26975597088cSDongdong Hao struct leapraid_fw_log_info *infom;
26985597088cSDongdong Hao struct leapraid_reg_base __iomem *iomem_base;
26995597088cSDongdong Hao unsigned long flags;
27005597088cSDongdong Hao
27015597088cSDongdong Hao if (leapraid_should_skip_poll_work(adapter))
27025597088cSDongdong Hao goto scheduled_timer;
27035597088cSDongdong Hao
27045597088cSDongdong Hao infom = (struct leapraid_fw_log_info *)
27055597088cSDongdong Hao (adapter->fw_log_desc.fw_log_buffer +
27065597088cSDongdong Hao LEAPRAID_SYS_LOG_BUF_SIZE);
27075597088cSDongdong Hao
27085597088cSDongdong Hao iomem_base = adapter->iomem_base;
27095597088cSDongdong Hao if (adapter->fw_log_desc.fw_log_init_flag == 0) {
27105597088cSDongdong Hao infom->user_position =
27115597088cSDongdong Hao leapraid_readl(&iomem_base->host_log_buf_pos);
27125597088cSDongdong Hao infom->adapter_position =
27135597088cSDongdong Hao leapraid_readl(&iomem_base->adapter_log_buf_pos);
27145597088cSDongdong Hao adapter->fw_log_desc.fw_log_init_flag++;
27155597088cSDongdong Hao }
27165597088cSDongdong Hao
27175597088cSDongdong Hao writel(infom->user_position, &iomem_base->host_log_buf_pos);
27185597088cSDongdong Hao infom->adapter_position =
27195597088cSDongdong Hao leapraid_readl(&iomem_base->adapter_log_buf_pos);
27205597088cSDongdong Hao
27215597088cSDongdong Hao scheduled_timer:
27225597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
27235597088cSDongdong Hao if (adapter->fw_log_desc.fw_log_wq)
27245597088cSDongdong Hao queue_delayed_work(
27255597088cSDongdong Hao adapter->fw_log_desc.fw_log_wq,
27265597088cSDongdong Hao &adapter->fw_log_desc.fw_log_work,
27275597088cSDongdong Hao msecs_to_jiffies(LEAPRAID_PCIE_LOG_POLLING_INTERVAL));
27285597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
27295597088cSDongdong Hao }
27305597088cSDongdong Hao
leapraid_fw_log_stop(struct leapraid_adapter * adapter)27315597088cSDongdong Hao void leapraid_fw_log_stop(struct leapraid_adapter *adapter)
27325597088cSDongdong Hao {
27335597088cSDongdong Hao struct workqueue_struct *wq;
27345597088cSDongdong Hao unsigned long flags;
27355597088cSDongdong Hao
27365597088cSDongdong Hao if (!adapter->fw_log_desc.open_pcie_trace)
27375597088cSDongdong Hao return;
27385597088cSDongdong Hao
27395597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
27405597088cSDongdong Hao wq = adapter->fw_log_desc.fw_log_wq;
27415597088cSDongdong Hao adapter->fw_log_desc.fw_log_wq = NULL;
27425597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
27435597088cSDongdong Hao if (wq) {
27445597088cSDongdong Hao if (!cancel_delayed_work_sync(&adapter->fw_log_desc
27455597088cSDongdong Hao .fw_log_work))
27465597088cSDongdong Hao flush_workqueue(wq);
27475597088cSDongdong Hao destroy_workqueue(wq);
27485597088cSDongdong Hao }
27495597088cSDongdong Hao }
27505597088cSDongdong Hao
leapraid_fw_log_start(struct leapraid_adapter * adapter)27515597088cSDongdong Hao void leapraid_fw_log_start(struct leapraid_adapter *adapter)
27525597088cSDongdong Hao {
27535597088cSDongdong Hao unsigned long flags;
27545597088cSDongdong Hao
27555597088cSDongdong Hao if (!adapter->fw_log_desc.open_pcie_trace)
27565597088cSDongdong Hao return;
27575597088cSDongdong Hao
27585597088cSDongdong Hao if (adapter->fw_log_desc.fw_log_wq)
27595597088cSDongdong Hao return;
27605597088cSDongdong Hao
27615597088cSDongdong Hao INIT_DELAYED_WORK(&adapter->fw_log_desc.fw_log_work,
27625597088cSDongdong Hao leapraid_fw_log_work);
27635597088cSDongdong Hao snprintf(adapter->fw_log_desc.fw_log_wq_name,
27645597088cSDongdong Hao sizeof(adapter->fw_log_desc.fw_log_wq_name),
27655597088cSDongdong Hao "poll_%s%u_fw_log",
27665597088cSDongdong Hao LEAPRAID_DRIVER_NAME, adapter->adapter_attr.id);
27675597088cSDongdong Hao adapter->fw_log_desc.fw_log_wq =
27685597088cSDongdong Hao create_singlethread_workqueue(
27695597088cSDongdong Hao adapter->fw_log_desc.fw_log_wq_name);
27705597088cSDongdong Hao if (!adapter->fw_log_desc.fw_log_wq)
27715597088cSDongdong Hao return;
27725597088cSDongdong Hao
27735597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
27745597088cSDongdong Hao if (adapter->fw_log_desc.fw_log_wq)
27755597088cSDongdong Hao queue_delayed_work(
27765597088cSDongdong Hao adapter->fw_log_desc.fw_log_wq,
27775597088cSDongdong Hao &adapter->fw_log_desc.fw_log_work,
27785597088cSDongdong Hao msecs_to_jiffies(LEAPRAID_PCIE_LOG_POLLING_INTERVAL));
27795597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
27805597088cSDongdong Hao }
27815597088cSDongdong Hao
leapraid_check_scheduled_fault_work(struct work_struct * work)27825597088cSDongdong Hao static void leapraid_check_scheduled_fault_work(struct work_struct *work)
27835597088cSDongdong Hao {
27845597088cSDongdong Hao struct leapraid_adapter *adapter;
27855597088cSDongdong Hao unsigned long flags;
27865597088cSDongdong Hao u32 adapter_state;
27875597088cSDongdong Hao int rc;
27885597088cSDongdong Hao
27895597088cSDongdong Hao adapter = container_of(work, struct leapraid_adapter,
27905597088cSDongdong Hao reset_desc.fault_reset_work.work);
27915597088cSDongdong Hao
27925597088cSDongdong Hao if (leapraid_should_skip_poll_work(adapter))
27935597088cSDongdong Hao goto scheduled_timer;
27945597088cSDongdong Hao
27955597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
27965597088cSDongdong Hao if (adapter_state != LEAPRAID_DB_OPERATIONAL) {
27975597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset 0x%x\n",
27985597088cSDongdong Hao __func__, __LINE__, adapter_state);
27995597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
28005597088cSDongdong Hao adapter_state = leapraid_get_adapter_state(adapter);
28015597088cSDongdong Hao if (rc && adapter_state != LEAPRAID_DB_OPERATIONAL) {
28025597088cSDongdong Hao dev_err(&adapter->pdev->dev,
28035597088cSDongdong Hao "%s: Hard reset failed, state=0x%x rc=%d\n",
28045597088cSDongdong Hao __func__, adapter_state, rc);
28055597088cSDongdong Hao return;
28065597088cSDongdong Hao }
28075597088cSDongdong Hao }
28085597088cSDongdong Hao
28095597088cSDongdong Hao scheduled_timer:
28105597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
28115597088cSDongdong Hao if (adapter->reset_desc.fault_reset_wq)
28125597088cSDongdong Hao queue_delayed_work(
28135597088cSDongdong Hao adapter->reset_desc.fault_reset_wq,
28145597088cSDongdong Hao &adapter->reset_desc.fault_reset_work,
28155597088cSDongdong Hao msecs_to_jiffies(LEAPRAID_FAULT_POLLING_INTERVAL));
28165597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
28175597088cSDongdong Hao }
28185597088cSDongdong Hao
leapraid_check_scheduled_fault_start(struct leapraid_adapter * adapter)28195597088cSDongdong Hao void leapraid_check_scheduled_fault_start(struct leapraid_adapter *adapter)
28205597088cSDongdong Hao {
28215597088cSDongdong Hao unsigned long flags;
28225597088cSDongdong Hao
28235597088cSDongdong Hao if (adapter->reset_desc.fault_reset_wq)
28245597088cSDongdong Hao return;
28255597088cSDongdong Hao
28265597088cSDongdong Hao INIT_DELAYED_WORK(&adapter->reset_desc.fault_reset_work,
28275597088cSDongdong Hao leapraid_check_scheduled_fault_work);
28285597088cSDongdong Hao snprintf(adapter->reset_desc.fault_reset_wq_name,
28295597088cSDongdong Hao sizeof(adapter->reset_desc.fault_reset_wq_name),
28305597088cSDongdong Hao "poll_%s%u_status",
28315597088cSDongdong Hao LEAPRAID_DRIVER_NAME, adapter->adapter_attr.id);
28325597088cSDongdong Hao adapter->reset_desc.fault_reset_wq =
28335597088cSDongdong Hao create_singlethread_workqueue(
28345597088cSDongdong Hao adapter->reset_desc.fault_reset_wq_name);
28355597088cSDongdong Hao if (!adapter->reset_desc.fault_reset_wq) {
28365597088cSDongdong Hao dev_err(&adapter->pdev->dev,
28375597088cSDongdong Hao "Create single thread workqueue failed!\n");
28385597088cSDongdong Hao return;
28395597088cSDongdong Hao }
28405597088cSDongdong Hao
28415597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
28425597088cSDongdong Hao if (adapter->reset_desc.fault_reset_wq)
28435597088cSDongdong Hao queue_delayed_work(
28445597088cSDongdong Hao adapter->reset_desc.fault_reset_wq,
28455597088cSDongdong Hao &adapter->reset_desc.fault_reset_work,
28465597088cSDongdong Hao msecs_to_jiffies(LEAPRAID_FAULT_POLLING_INTERVAL));
28475597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
28485597088cSDongdong Hao }
28495597088cSDongdong Hao
leapraid_check_scheduled_fault_stop(struct leapraid_adapter * adapter)28505597088cSDongdong Hao void leapraid_check_scheduled_fault_stop(struct leapraid_adapter *adapter)
28515597088cSDongdong Hao {
28525597088cSDongdong Hao struct workqueue_struct *wq;
28535597088cSDongdong Hao unsigned long flags;
28545597088cSDongdong Hao
28555597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
28565597088cSDongdong Hao wq = adapter->reset_desc.fault_reset_wq;
28575597088cSDongdong Hao adapter->reset_desc.fault_reset_wq = NULL;
28585597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
28595597088cSDongdong Hao
28605597088cSDongdong Hao if (!wq)
28615597088cSDongdong Hao return;
28625597088cSDongdong Hao
28635597088cSDongdong Hao if (!cancel_delayed_work_sync(&adapter->reset_desc.fault_reset_work))
28645597088cSDongdong Hao flush_workqueue(wq);
28655597088cSDongdong Hao destroy_workqueue(wq);
28665597088cSDongdong Hao }
28675597088cSDongdong Hao
leapraid_overheat_work(struct work_struct * work)28685597088cSDongdong Hao static void leapraid_overheat_work(struct work_struct *work)
28695597088cSDongdong Hao {
28705597088cSDongdong Hao struct leapraid_overheat_desc *desc;
28715597088cSDongdong Hao struct leapraid_adapter *adapter;
28725597088cSDongdong Hao struct workqueue_struct *wq;
28735597088cSDongdong Hao struct Scsi_Host *shost;
28745597088cSDongdong Hao struct pci_dev *pdev;
28755597088cSDongdong Hao unsigned long flags;
28765597088cSDongdong Hao
28775597088cSDongdong Hao desc = container_of(work, struct leapraid_overheat_desc,
28785597088cSDongdong Hao fault_overheat_work);
28795597088cSDongdong Hao adapter = container_of(desc, struct leapraid_adapter, overheat_desc);
28805597088cSDongdong Hao pdev = adapter->pdev;
28815597088cSDongdong Hao shost = pci_get_drvdata(pdev);
28825597088cSDongdong Hao
28835597088cSDongdong Hao if (!shost) {
28845597088cSDongdong Hao dev_err(&pdev->dev,
28855597088cSDongdong Hao "Overheat processing failed: invalid host/adapter\n");
28865597088cSDongdong Hao atomic_set(&adapter->overheat_desc.thermal_alert, 0);
28875597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
28885597088cSDongdong Hao return;
28895597088cSDongdong Hao }
28905597088cSDongdong Hao
28915597088cSDongdong Hao if (adapter->access_ctrl.host_removing) {
28925597088cSDongdong Hao atomic_set(&adapter->overheat_desc.thermal_alert, 0);
28935597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
28945597088cSDongdong Hao return;
28955597088cSDongdong Hao }
28965597088cSDongdong Hao
28975597088cSDongdong Hao adapter->access_ctrl.host_removing = 1;
28985597088cSDongdong Hao adapter->access_ctrl.shost_recover_async = 0;
28995597088cSDongdong Hao adapter->scan_dev_desc.scan_start = 0;
29005597088cSDongdong Hao adapter->scan_dev_desc.wait_scan_dev_done = 0;
29015597088cSDongdong Hao adapter->scan_dev_desc.driver_loading = 0;
29025597088cSDongdong Hao wake_up(&adapter->access_ctrl.shost_recover_wq);
29035597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
29045597088cSDongdong Hao
29055597088cSDongdong Hao leapraid_mask_int(adapter);
29065597088cSDongdong Hao
29075597088cSDongdong Hao leapraid_check_scheduled_fault_stop(adapter);
29085597088cSDongdong Hao leapraid_fw_log_stop(adapter);
29095597088cSDongdong Hao leapraid_mq_polling_pause(adapter);
29105597088cSDongdong Hao
29115597088cSDongdong Hao leapraid_clean_active_cmds(adapter);
29125597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
29135597088cSDongdong Hao wq = adapter->fw_evt_s.fw_evt_thread;
29145597088cSDongdong Hao adapter->fw_evt_s.fw_evt_thread = NULL;
29155597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
29165597088cSDongdong Hao if (wq)
29175597088cSDongdong Hao destroy_workqueue(wq);
29185597088cSDongdong Hao
29195597088cSDongdong Hao sas_remove_host(shost);
29205597088cSDongdong Hao leapraid_cleanup_lists(adapter);
29215597088cSDongdong Hao atomic_set(&adapter->overheat_desc.thermal_alert, 0);
29225597088cSDongdong Hao wake_up(&adapter->scan_dev_desc.wait_driver_loading);
29235597088cSDongdong Hao dev_err(&pdev->dev, "%s: Suspend adapter due to overheat\n", __func__);
29245597088cSDongdong Hao }
29255597088cSDongdong Hao
leapraid_overheat_init(struct leapraid_adapter * adapter)29265597088cSDongdong Hao static void leapraid_overheat_init(struct leapraid_adapter *adapter)
29275597088cSDongdong Hao {
29285597088cSDongdong Hao if (adapter->overheat_desc.fault_overheat_wq)
29295597088cSDongdong Hao return;
29305597088cSDongdong Hao
29315597088cSDongdong Hao atomic_set(&adapter->overheat_desc.thermal_alert, 0);
29325597088cSDongdong Hao snprintf(adapter->overheat_desc.fault_overheat_wq_name,
29335597088cSDongdong Hao sizeof(adapter->overheat_desc.fault_overheat_wq_name),
29345597088cSDongdong Hao "driver_%s%u_overheat",
29355597088cSDongdong Hao LEAPRAID_DRIVER_NAME,
29365597088cSDongdong Hao adapter->adapter_attr.id);
29375597088cSDongdong Hao adapter->overheat_desc.fault_overheat_wq =
29385597088cSDongdong Hao create_singlethread_workqueue(
29395597088cSDongdong Hao adapter->overheat_desc.fault_overheat_wq_name);
29405597088cSDongdong Hao if (!adapter->overheat_desc.fault_overheat_wq) {
29415597088cSDongdong Hao dev_err(&adapter->pdev->dev,
29425597088cSDongdong Hao "Failed to create overheat workqueue\n");
29435597088cSDongdong Hao return;
29445597088cSDongdong Hao }
29455597088cSDongdong Hao
29465597088cSDongdong Hao INIT_WORK(&adapter->overheat_desc.fault_overheat_work,
29475597088cSDongdong Hao leapraid_overheat_work);
29485597088cSDongdong Hao }
29495597088cSDongdong Hao
leapraid_overheat_cleanup(struct leapraid_adapter * adapter)29505597088cSDongdong Hao void leapraid_overheat_cleanup(struct leapraid_adapter *adapter)
29515597088cSDongdong Hao {
29525597088cSDongdong Hao struct workqueue_struct *wq;
29535597088cSDongdong Hao
29545597088cSDongdong Hao wq = xchg(&adapter->overheat_desc.fault_overheat_wq, NULL);
29555597088cSDongdong Hao if (!wq)
29565597088cSDongdong Hao return;
29575597088cSDongdong Hao
29585597088cSDongdong Hao cancel_work_sync(&adapter->overheat_desc.fault_overheat_work);
29595597088cSDongdong Hao destroy_workqueue(wq);
29605597088cSDongdong Hao }
29615597088cSDongdong Hao
29625597088cSDongdong Hao static void leapraid_fw_work(struct leapraid_adapter *adapter,
29635597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt);
29645597088cSDongdong Hao
leapraid_fw_evt_free(struct kref * r)29655597088cSDongdong Hao static void leapraid_fw_evt_free(struct kref *r)
29665597088cSDongdong Hao {
29675597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt;
29685597088cSDongdong Hao
29695597088cSDongdong Hao fw_evt = container_of(r, struct leapraid_fw_evt_work, refcnt);
29705597088cSDongdong Hao
29715597088cSDongdong Hao kfree(fw_evt->evt_data);
29725597088cSDongdong Hao kfree(fw_evt);
29735597088cSDongdong Hao }
29745597088cSDongdong Hao
leapraid_fw_evt_get(struct leapraid_fw_evt_work * fw_evt)29755597088cSDongdong Hao static void leapraid_fw_evt_get(struct leapraid_fw_evt_work *fw_evt)
29765597088cSDongdong Hao {
29775597088cSDongdong Hao kref_get(&fw_evt->refcnt);
29785597088cSDongdong Hao }
29795597088cSDongdong Hao
leapraid_fw_evt_put(struct leapraid_fw_evt_work * fw_work)29805597088cSDongdong Hao static void leapraid_fw_evt_put(struct leapraid_fw_evt_work *fw_work)
29815597088cSDongdong Hao {
29825597088cSDongdong Hao kref_put(&fw_work->refcnt, leapraid_fw_evt_free);
29835597088cSDongdong Hao }
29845597088cSDongdong Hao
leapraid_alloc_fw_evt_work(void)29855597088cSDongdong Hao static struct leapraid_fw_evt_work *leapraid_alloc_fw_evt_work(void)
29865597088cSDongdong Hao {
29875597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt =
29885597088cSDongdong Hao kzalloc(sizeof(*fw_evt), GFP_ATOMIC);
29895597088cSDongdong Hao
29905597088cSDongdong Hao if (fw_evt)
29915597088cSDongdong Hao kref_init(&fw_evt->refcnt);
29925597088cSDongdong Hao
29935597088cSDongdong Hao return fw_evt;
29945597088cSDongdong Hao }
29955597088cSDongdong Hao
leapraid_run_fw_evt_work(struct work_struct * work)29965597088cSDongdong Hao static void leapraid_run_fw_evt_work(struct work_struct *work)
29975597088cSDongdong Hao {
29985597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt =
29995597088cSDongdong Hao container_of(work, struct leapraid_fw_evt_work, work);
30005597088cSDongdong Hao
30015597088cSDongdong Hao leapraid_fw_work(fw_evt->adapter, fw_evt);
30025597088cSDongdong Hao }
30035597088cSDongdong Hao
leapraid_fw_evt_add(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)30045597088cSDongdong Hao static void leapraid_fw_evt_add(struct leapraid_adapter *adapter,
30055597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
30065597088cSDongdong Hao {
30075597088cSDongdong Hao unsigned long flags;
30085597088cSDongdong Hao
30095597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
30105597088cSDongdong Hao if (adapter->access_ctrl.host_removing ||
30115597088cSDongdong Hao adapter->access_ctrl.pcie_recovering ||
30125597088cSDongdong Hao !adapter->fw_evt_s.fw_evt_thread) {
30135597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
30145597088cSDongdong Hao return;
30155597088cSDongdong Hao }
30165597088cSDongdong Hao
30175597088cSDongdong Hao leapraid_fw_evt_get(fw_evt);
30185597088cSDongdong Hao INIT_LIST_HEAD(&fw_evt->list);
30195597088cSDongdong Hao list_add_tail(&fw_evt->list, &adapter->fw_evt_s.fw_evt_list);
30205597088cSDongdong Hao INIT_WORK(&fw_evt->work, leapraid_run_fw_evt_work);
30215597088cSDongdong Hao leapraid_fw_evt_get(fw_evt);
30225597088cSDongdong Hao queue_work(adapter->fw_evt_s.fw_evt_thread, &fw_evt->work);
30235597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
30245597088cSDongdong Hao }
30255597088cSDongdong Hao
leapraid_del_fw_evt_from_list(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)30265597088cSDongdong Hao static void leapraid_del_fw_evt_from_list(struct leapraid_adapter *adapter,
30275597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
30285597088cSDongdong Hao {
30295597088cSDongdong Hao unsigned long flags;
30305597088cSDongdong Hao
30315597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
30325597088cSDongdong Hao if (!list_empty(&fw_evt->list)) {
30335597088cSDongdong Hao list_del_init(&fw_evt->list);
30345597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
30355597088cSDongdong Hao }
30365597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
30375597088cSDongdong Hao }
30385597088cSDongdong Hao
leapraid_next_fw_evt(struct leapraid_adapter * adapter)30395597088cSDongdong Hao static struct leapraid_fw_evt_work *leapraid_next_fw_evt(
30405597088cSDongdong Hao struct leapraid_adapter *adapter)
30415597088cSDongdong Hao {
30425597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt = NULL;
30435597088cSDongdong Hao unsigned long flags;
30445597088cSDongdong Hao
30455597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
30465597088cSDongdong Hao if (!list_empty(&adapter->fw_evt_s.fw_evt_list)) {
30475597088cSDongdong Hao fw_evt = list_first_entry(&adapter->fw_evt_s.fw_evt_list,
30485597088cSDongdong Hao struct leapraid_fw_evt_work, list);
30495597088cSDongdong Hao list_del_init(&fw_evt->list);
30505597088cSDongdong Hao }
30515597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
30525597088cSDongdong Hao return fw_evt;
30535597088cSDongdong Hao }
30545597088cSDongdong Hao
leapraid_clean_active_fw_evt(struct leapraid_adapter * adapter)30555597088cSDongdong Hao void leapraid_clean_active_fw_evt(struct leapraid_adapter *adapter)
30565597088cSDongdong Hao {
30575597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt;
30585597088cSDongdong Hao unsigned long flags;
30595597088cSDongdong Hao bool in_fw_evt_context;
30605597088cSDongdong Hao bool rc;
30615597088cSDongdong Hao
30625597088cSDongdong Hao if ((list_empty(&adapter->fw_evt_s.fw_evt_list) &&
30635597088cSDongdong Hao !adapter->fw_evt_s.cur_evt) || !adapter->fw_evt_s.fw_evt_thread)
30645597088cSDongdong Hao return;
30655597088cSDongdong Hao
30665597088cSDongdong Hao adapter->fw_evt_s.fw_evt_cleanup = 1;
30675597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering &&
30685597088cSDongdong Hao adapter->fw_evt_s.cur_evt)
30695597088cSDongdong Hao adapter->fw_evt_s.cur_evt->ignore = 1;
30705597088cSDongdong Hao
30715597088cSDongdong Hao while ((fw_evt = leapraid_next_fw_evt(adapter))) {
30725597088cSDongdong Hao rc = cancel_work_sync(&fw_evt->work);
30735597088cSDongdong Hao if (rc)
30745597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
30755597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
30765597088cSDongdong Hao }
30775597088cSDongdong Hao
30785597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
30795597088cSDongdong Hao fw_evt = adapter->fw_evt_s.cur_evt;
30805597088cSDongdong Hao if (fw_evt) {
30815597088cSDongdong Hao in_fw_evt_context = adapter->fw_evt_s.cur_evt_task == current;
30825597088cSDongdong Hao leapraid_fw_evt_get(fw_evt);
30835597088cSDongdong Hao }
30845597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
30855597088cSDongdong Hao if (fw_evt) {
30865597088cSDongdong Hao if (!in_fw_evt_context)
30875597088cSDongdong Hao cancel_work_sync(&fw_evt->work);
30885597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
30895597088cSDongdong Hao }
30905597088cSDongdong Hao
30915597088cSDongdong Hao adapter->fw_evt_s.fw_evt_cleanup = 0;
30925597088cSDongdong Hao }
30935597088cSDongdong Hao
leapraid_internal_dev_ublk(struct scsi_device * sdev,struct leapraid_sdev_priv * sdev_priv)30945597088cSDongdong Hao static void leapraid_internal_dev_ublk(struct scsi_device *sdev,
30955597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv)
30965597088cSDongdong Hao {
30975597088cSDongdong Hao int rc;
30985597088cSDongdong Hao
30995597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
31005597088cSDongdong Hao "hdl 0x%04x: Now internal unblkg dev\n",
31015597088cSDongdong Hao sdev_priv->starget_priv->hdl);
31025597088cSDongdong Hao sdev_priv->block = 0;
31035597088cSDongdong Hao rc = scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
31045597088cSDongdong Hao if (rc == -EINVAL) {
31055597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
31065597088cSDongdong Hao "hdl 0x%04x: unblkg failed, rc=%d\n",
31075597088cSDongdong Hao sdev_priv->starget_priv->hdl, rc);
31085597088cSDongdong Hao sdev_priv->block = 1;
31095597088cSDongdong Hao rc = scsi_internal_device_block_nowait(sdev);
31105597088cSDongdong Hao if (rc)
31115597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
31125597088cSDongdong Hao "hdl 0x%04x: Earlier ublkg err, rc=%d\n",
31135597088cSDongdong Hao sdev_priv->starget_priv->hdl, rc);
31145597088cSDongdong Hao
31155597088cSDongdong Hao sdev_priv->block = 0;
31165597088cSDongdong Hao rc = scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING);
31175597088cSDongdong Hao if (rc)
31185597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
31195597088cSDongdong Hao "hdl 0x%04x: ublkg failed again, rc=%d\n",
31205597088cSDongdong Hao sdev_priv->starget_priv->hdl, rc);
31215597088cSDongdong Hao }
31225597088cSDongdong Hao }
31235597088cSDongdong Hao
leapraid_ublk_io_dev(struct leapraid_adapter * adapter,u64 sas_addr,struct leapraid_card_port * card_port)31245597088cSDongdong Hao static void leapraid_ublk_io_dev(struct leapraid_adapter *adapter,
31255597088cSDongdong Hao u64 sas_addr,
31265597088cSDongdong Hao struct leapraid_card_port *card_port)
31275597088cSDongdong Hao {
31285597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
31295597088cSDongdong Hao struct scsi_device *sdev;
31305597088cSDongdong Hao
31315597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
31325597088cSDongdong Hao sdev_priv = sdev->hostdata;
31335597088cSDongdong Hao if (!sdev_priv || !sdev_priv->starget_priv)
31345597088cSDongdong Hao continue;
31355597088cSDongdong Hao
31365597088cSDongdong Hao if (sdev_priv->starget_priv->sas_address != sas_addr)
31375597088cSDongdong Hao continue;
31385597088cSDongdong Hao
31395597088cSDongdong Hao if (sdev_priv->starget_priv->card_port != card_port)
31405597088cSDongdong Hao continue;
31415597088cSDongdong Hao
31425597088cSDongdong Hao if (sdev_priv->block)
31435597088cSDongdong Hao leapraid_internal_dev_ublk(sdev, sdev_priv);
31445597088cSDongdong Hao
31455597088cSDongdong Hao scsi_device_set_state(sdev, SDEV_OFFLINE);
31465597088cSDongdong Hao }
31475597088cSDongdong Hao }
31485597088cSDongdong Hao
leapraid_ublk_io_all_dev(struct leapraid_adapter * adapter)31495597088cSDongdong Hao static void leapraid_ublk_io_all_dev(struct leapraid_adapter *adapter)
31505597088cSDongdong Hao {
31515597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
31525597088cSDongdong Hao struct leapraid_starget_priv *stgt_priv;
31535597088cSDongdong Hao struct scsi_device *sdev;
31545597088cSDongdong Hao
31555597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
31565597088cSDongdong Hao sdev_priv = sdev->hostdata;
31575597088cSDongdong Hao
31585597088cSDongdong Hao if (!sdev_priv)
31595597088cSDongdong Hao continue;
31605597088cSDongdong Hao
31615597088cSDongdong Hao stgt_priv = sdev_priv->starget_priv;
31625597088cSDongdong Hao if (!stgt_priv || stgt_priv->deleted)
31635597088cSDongdong Hao continue;
31645597088cSDongdong Hao
31655597088cSDongdong Hao if (!sdev_priv->block)
31665597088cSDongdong Hao continue;
31675597088cSDongdong Hao
31685597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev, "hdl 0x%04x: blkg...\n",
31695597088cSDongdong Hao sdev_priv->starget_priv->hdl);
31705597088cSDongdong Hao leapraid_internal_dev_ublk(sdev, sdev_priv);
31715597088cSDongdong Hao continue;
31725597088cSDongdong Hao }
31735597088cSDongdong Hao }
31745597088cSDongdong Hao
leapraid_internal_dev_blk(struct scsi_device * sdev,struct leapraid_sdev_priv * sdev_priv)31755597088cSDongdong Hao static void leapraid_internal_dev_blk(
31765597088cSDongdong Hao struct scsi_device *sdev,
31775597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv)
31785597088cSDongdong Hao {
31795597088cSDongdong Hao int rc;
31805597088cSDongdong Hao
31815597088cSDongdong Hao sdev_printk(KERN_INFO, sdev, "Internal blkg hdl 0x%04x\n",
31825597088cSDongdong Hao sdev_priv->starget_priv->hdl);
31835597088cSDongdong Hao sdev_priv->block = 1;
31845597088cSDongdong Hao rc = scsi_internal_device_block_nowait(sdev);
31855597088cSDongdong Hao if (rc == -EINVAL)
31865597088cSDongdong Hao sdev_printk(KERN_WARNING, sdev,
31875597088cSDongdong Hao "hdl 0x%04x: blkg failed, rc=%d\n",
31885597088cSDongdong Hao rc, sdev_priv->starget_priv->hdl);
31895597088cSDongdong Hao }
31905597088cSDongdong Hao
leapraid_imm_blkio_to_end_dev(struct leapraid_adapter * adapter,struct leapraid_sas_port * sas_port)31915597088cSDongdong Hao static void leapraid_imm_blkio_to_end_dev(struct leapraid_adapter *adapter,
31925597088cSDongdong Hao struct leapraid_sas_port *sas_port)
31935597088cSDongdong Hao {
31945597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
31955597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
31965597088cSDongdong Hao struct scsi_device *sdev;
31975597088cSDongdong Hao unsigned long flags;
31985597088cSDongdong Hao
31995597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
32005597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(
32015597088cSDongdong Hao adapter,
32025597088cSDongdong Hao sas_port->remote_identify.sas_address,
32035597088cSDongdong Hao sas_port->card_port);
32045597088cSDongdong Hao
32055597088cSDongdong Hao if (sas_dev) {
32065597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
32075597088cSDongdong Hao sdev_priv = sdev->hostdata;
32085597088cSDongdong Hao if (!sdev_priv)
32095597088cSDongdong Hao continue;
32105597088cSDongdong Hao
32115597088cSDongdong Hao if (sdev_priv->starget_priv->hdl != sas_dev->hdl)
32125597088cSDongdong Hao continue;
32135597088cSDongdong Hao
32145597088cSDongdong Hao if (sdev_priv->block)
32155597088cSDongdong Hao continue;
32165597088cSDongdong Hao
32175597088cSDongdong Hao if (sas_dev && sas_dev->pend_sas_rphy_add)
32185597088cSDongdong Hao continue;
32195597088cSDongdong Hao
32205597088cSDongdong Hao if (sdev_priv->sep) {
32215597088cSDongdong Hao sdev_printk(KERN_INFO, sdev,
32225597088cSDongdong Hao "skip dev blk: sep hdl 0x%04x\n",
32235597088cSDongdong Hao sdev_priv->starget_priv->hdl);
32245597088cSDongdong Hao continue;
32255597088cSDongdong Hao }
32265597088cSDongdong Hao
32275597088cSDongdong Hao leapraid_internal_dev_blk(sdev, sdev_priv);
32285597088cSDongdong Hao }
32295597088cSDongdong Hao
32305597088cSDongdong Hao leapraid_sdev_put(sas_dev);
32315597088cSDongdong Hao }
32325597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
32335597088cSDongdong Hao }
32345597088cSDongdong Hao
leapraid_imm_blkio_set_end_dev_blk_hdls(struct leapraid_adapter * adapter,struct leapraid_topo_node * topo_node_exp)32355597088cSDongdong Hao static void leapraid_imm_blkio_set_end_dev_blk_hdls(
32365597088cSDongdong Hao struct leapraid_adapter *adapter,
32375597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp)
32385597088cSDongdong Hao {
32395597088cSDongdong Hao struct leapraid_sas_port *sas_port;
32405597088cSDongdong Hao
32415597088cSDongdong Hao list_for_each_entry(sas_port,
32425597088cSDongdong Hao &topo_node_exp->sas_port_list, port_list) {
32435597088cSDongdong Hao if (sas_port->remote_identify.device_type == SAS_END_DEVICE)
32445597088cSDongdong Hao leapraid_imm_blkio_to_end_dev(adapter, sas_port);
32455597088cSDongdong Hao }
32465597088cSDongdong Hao }
32475597088cSDongdong Hao
32485597088cSDongdong Hao static void leapraid_imm_blkio_to_kids_attchd_to_ex(
32495597088cSDongdong Hao struct leapraid_adapter *adapter,
32505597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp);
32515597088cSDongdong Hao
leapraid_imm_blkio_to_sib_exp(struct leapraid_adapter * adapter,struct leapraid_topo_node * topo_node_exp)32525597088cSDongdong Hao static void leapraid_imm_blkio_to_sib_exp(
32535597088cSDongdong Hao struct leapraid_adapter *adapter,
32545597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp)
32555597088cSDongdong Hao {
32565597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp_sib;
32575597088cSDongdong Hao struct leapraid_sas_port *sas_port;
32585597088cSDongdong Hao
32595597088cSDongdong Hao list_for_each_entry(sas_port,
32605597088cSDongdong Hao &topo_node_exp->sas_port_list, port_list) {
32615597088cSDongdong Hao if (sas_port->remote_identify.device_type ==
32625597088cSDongdong Hao SAS_EDGE_EXPANDER_DEVICE ||
32635597088cSDongdong Hao sas_port->remote_identify.device_type ==
32645597088cSDongdong Hao SAS_FANOUT_EXPANDER_DEVICE) {
32655597088cSDongdong Hao topo_node_exp_sib =
32665597088cSDongdong Hao leapraid_exp_find_by_sas_address(
32675597088cSDongdong Hao adapter,
32685597088cSDongdong Hao sas_port->remote_identify.sas_address,
32695597088cSDongdong Hao sas_port->card_port);
32705597088cSDongdong Hao leapraid_imm_blkio_to_kids_attchd_to_ex(
32715597088cSDongdong Hao adapter,
32725597088cSDongdong Hao topo_node_exp_sib);
32735597088cSDongdong Hao }
32745597088cSDongdong Hao }
32755597088cSDongdong Hao }
32765597088cSDongdong Hao
leapraid_imm_blkio_to_kids_attchd_to_ex(struct leapraid_adapter * adapter,struct leapraid_topo_node * topo_node_exp)32775597088cSDongdong Hao static void leapraid_imm_blkio_to_kids_attchd_to_ex(
32785597088cSDongdong Hao struct leapraid_adapter *adapter,
32795597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp)
32805597088cSDongdong Hao {
32815597088cSDongdong Hao if (!topo_node_exp)
32825597088cSDongdong Hao return;
32835597088cSDongdong Hao
32845597088cSDongdong Hao leapraid_imm_blkio_set_end_dev_blk_hdls(adapter, topo_node_exp);
32855597088cSDongdong Hao
32865597088cSDongdong Hao leapraid_imm_blkio_to_sib_exp(adapter, topo_node_exp);
32875597088cSDongdong Hao }
32885597088cSDongdong Hao
leapraid_report_sdev_directly(struct leapraid_adapter * adapter,struct leapraid_sas_dev * sas_dev)32895597088cSDongdong Hao static void leapraid_report_sdev_directly(struct leapraid_adapter *adapter,
32905597088cSDongdong Hao struct leapraid_sas_dev *sas_dev)
32915597088cSDongdong Hao {
32925597088cSDongdong Hao struct leapraid_sas_port *sas_port;
32935597088cSDongdong Hao
32945597088cSDongdong Hao sas_port = leapraid_transport_port_add(adapter,
32955597088cSDongdong Hao sas_dev->hdl,
32965597088cSDongdong Hao sas_dev->parent_sas_addr,
32975597088cSDongdong Hao sas_dev->card_port);
32985597088cSDongdong Hao if (!sas_port) {
32995597088cSDongdong Hao leapraid_sas_dev_remove(adapter, sas_dev);
33005597088cSDongdong Hao return;
33015597088cSDongdong Hao }
33025597088cSDongdong Hao
33035597088cSDongdong Hao if (!sas_dev->starget) {
33045597088cSDongdong Hao if (!adapter->scan_dev_desc.driver_loading) {
33055597088cSDongdong Hao leapraid_transport_port_remove(
33065597088cSDongdong Hao adapter,
33075597088cSDongdong Hao sas_dev->sas_addr,
33085597088cSDongdong Hao sas_dev->parent_sas_addr,
33095597088cSDongdong Hao sas_dev->card_port);
33105597088cSDongdong Hao leapraid_sas_dev_remove(adapter, sas_dev);
33115597088cSDongdong Hao }
33125597088cSDongdong Hao return;
33135597088cSDongdong Hao }
33145597088cSDongdong Hao }
33155597088cSDongdong Hao
leapraid_init_sas_dev(struct leapraid_adapter * adapter,struct leapraid_sas_dev_p0 * sas_dev_pg0,struct leapraid_card_port * card_port,u16 hdl,u64 parent_sas_addr,u64 sas_addr,u32 dev_info)33165597088cSDongdong Hao static struct leapraid_sas_dev *leapraid_init_sas_dev(
33175597088cSDongdong Hao struct leapraid_adapter *adapter,
33185597088cSDongdong Hao struct leapraid_sas_dev_p0 *sas_dev_pg0,
33195597088cSDongdong Hao struct leapraid_card_port *card_port, u16 hdl,
33205597088cSDongdong Hao u64 parent_sas_addr, u64 sas_addr, u32 dev_info)
33215597088cSDongdong Hao {
33225597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
33235597088cSDongdong Hao struct leapraid_enc_node *enc_dev;
33245597088cSDongdong Hao unsigned long flags;
33255597088cSDongdong Hao
33265597088cSDongdong Hao sas_dev = kzalloc_obj(*sas_dev);
33275597088cSDongdong Hao if (!sas_dev)
33285597088cSDongdong Hao return NULL;
33295597088cSDongdong Hao
33305597088cSDongdong Hao kref_init(&sas_dev->refcnt);
33315597088cSDongdong Hao sas_dev->hdl = hdl;
33325597088cSDongdong Hao sas_dev->dev_info = dev_info;
33335597088cSDongdong Hao sas_dev->sas_addr = sas_addr;
33345597088cSDongdong Hao sas_dev->card_port = card_port;
33355597088cSDongdong Hao sas_dev->parent_sas_addr = parent_sas_addr;
33365597088cSDongdong Hao sas_dev->phy = sas_dev_pg0->phy_num;
33375597088cSDongdong Hao sas_dev->enc_hdl = le16_to_cpu(sas_dev_pg0->enc_hdl);
33385597088cSDongdong Hao sas_dev->dev_name = le64_to_cpu(sas_dev_pg0->dev_name);
33395597088cSDongdong Hao sas_dev->port_connection = sas_dev_pg0->max_port_connections;
33405597088cSDongdong Hao sas_dev->slot = sas_dev->enc_hdl ? le16_to_cpu(sas_dev_pg0->slot) : 0;
33415597088cSDongdong Hao if (le16_to_cpu(sas_dev_pg0->flg) &
33425597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_FLG_ENC_LEVEL_VALID) {
33435597088cSDongdong Hao sas_dev->enc_level = sas_dev_pg0->enc_level;
33445597088cSDongdong Hao memcpy(sas_dev->connector_name,
33455597088cSDongdong Hao sas_dev_pg0->connector_name,
33465597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_CON_NAME_LEN);
33475597088cSDongdong Hao sas_dev->connector_name[LEAPRAID_SAS_DEV_P0_CON_NAME_LEN] =
33485597088cSDongdong Hao '\0';
33495597088cSDongdong Hao } else {
33505597088cSDongdong Hao sas_dev->enc_level = 0;
33515597088cSDongdong Hao sas_dev->connector_name[0] = '\0';
33525597088cSDongdong Hao }
33535597088cSDongdong Hao if (sas_dev->enc_hdl) {
33545597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
33555597088cSDongdong Hao enc_dev = leapraid_enc_find_by_hdl(adapter, sas_dev->enc_hdl);
33565597088cSDongdong Hao if (enc_dev)
33575597088cSDongdong Hao sas_dev->enc_lid = le64_to_cpu(enc_dev->pg0.enc_lid);
33585597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
33595597088cSDongdong Hao }
33605597088cSDongdong Hao dev_info(&adapter->pdev->dev,
33615597088cSDongdong Hao "add dev: hdl=0x%x, SAS addr=0x%016llx, port connect=0x%x\n",
33625597088cSDongdong Hao hdl, sas_dev->sas_addr, sas_dev->port_connection);
33635597088cSDongdong Hao
33645597088cSDongdong Hao return sas_dev;
33655597088cSDongdong Hao }
33665597088cSDongdong Hao
leapraid_add_dev(struct leapraid_adapter * adapter,u16 hdl)33675597088cSDongdong Hao static void leapraid_add_dev(struct leapraid_adapter *adapter, u16 hdl)
33685597088cSDongdong Hao {
33695597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
33705597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
33715597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_pg0;
33725597088cSDongdong Hao struct leapraid_card_port *card_port;
33735597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
33745597088cSDongdong Hao unsigned long flags;
33755597088cSDongdong Hao u64 parent_sas_addr;
33765597088cSDongdong Hao u32 dev_info;
33775597088cSDongdong Hao u64 sas_addr;
33785597088cSDongdong Hao u8 port_id;
33795597088cSDongdong Hao
33805597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
33815597088cSDongdong Hao cfgp2.handle = hdl;
33825597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_pg0,
33835597088cSDongdong Hao cfgp1, cfgp2, GET_SAS_DEVICE_PG0))
33845597088cSDongdong Hao return;
33855597088cSDongdong Hao
33865597088cSDongdong Hao dev_info = le32_to_cpu(sas_dev_pg0.dev_info);
33875597088cSDongdong Hao if (!(leapraid_is_end_dev(dev_info)))
33885597088cSDongdong Hao return;
33895597088cSDongdong Hao
33905597088cSDongdong Hao sas_addr = le64_to_cpu(sas_dev_pg0.sas_address);
33915597088cSDongdong Hao if (!(le16_to_cpu(sas_dev_pg0.flg) &
33925597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_FLG_DEV_PRESENT))
33935597088cSDongdong Hao return;
33945597088cSDongdong Hao
33955597088cSDongdong Hao port_id = sas_dev_pg0.physical_port;
33965597088cSDongdong Hao card_port = leapraid_get_port_by_id(adapter, port_id, false);
33975597088cSDongdong Hao if (!card_port)
33985597088cSDongdong Hao return;
33995597088cSDongdong Hao
34005597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_addr(adapter, sas_addr, card_port);
34015597088cSDongdong Hao if (sas_dev) {
34025597088cSDongdong Hao leapraid_sdev_put(sas_dev);
34035597088cSDongdong Hao return;
34045597088cSDongdong Hao }
34055597088cSDongdong Hao
34065597088cSDongdong Hao if (leapraid_get_sas_address(adapter,
34075597088cSDongdong Hao le16_to_cpu(sas_dev_pg0.parent_dev_hdl),
34085597088cSDongdong Hao &parent_sas_addr))
34095597088cSDongdong Hao return;
34105597088cSDongdong Hao
34115597088cSDongdong Hao sas_dev = leapraid_init_sas_dev(adapter, &sas_dev_pg0, card_port,
34125597088cSDongdong Hao hdl, parent_sas_addr, sas_addr,
34135597088cSDongdong Hao dev_info);
34145597088cSDongdong Hao if (!sas_dev)
34155597088cSDongdong Hao return;
34165597088cSDongdong Hao
34175597088cSDongdong Hao if (adapter->scan_dev_desc.wait_scan_dev_done) {
34185597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
34195597088cSDongdong Hao leapraid_sdev_get(sas_dev);
34205597088cSDongdong Hao list_add_tail(&sas_dev->list,
34215597088cSDongdong Hao &adapter->dev_topo.sas_dev_init_list);
34225597088cSDongdong Hao leapraid_check_boot_dev(adapter, sas_dev, 0);
34235597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
34245597088cSDongdong Hao } else {
34255597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
34265597088cSDongdong Hao leapraid_sdev_get(sas_dev);
34275597088cSDongdong Hao list_add_tail(&sas_dev->list, &adapter->dev_topo.sas_dev_list);
34285597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
34295597088cSDongdong Hao leapraid_report_sdev_directly(adapter, sas_dev);
34305597088cSDongdong Hao }
34315597088cSDongdong Hao leapraid_sdev_put(sas_dev);
34325597088cSDongdong Hao }
34335597088cSDongdong Hao
leapraid_remove_device(struct leapraid_adapter * adapter,struct leapraid_sas_dev * sas_dev)34345597088cSDongdong Hao static void leapraid_remove_device(struct leapraid_adapter *adapter,
34355597088cSDongdong Hao struct leapraid_sas_dev *sas_dev)
34365597088cSDongdong Hao {
34375597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
34385597088cSDongdong Hao
34395597088cSDongdong Hao leapraid_clear_cached_boot_dev(adapter, sas_dev, 0);
34405597088cSDongdong Hao if (sas_dev->led_on) {
34415597088cSDongdong Hao leapraid_set_led(adapter, sas_dev, false);
34425597088cSDongdong Hao sas_dev->led_on = 0;
34435597088cSDongdong Hao }
34445597088cSDongdong Hao
34455597088cSDongdong Hao if (sas_dev->starget && sas_dev->starget->hostdata) {
34465597088cSDongdong Hao starget_priv = sas_dev->starget->hostdata;
34475597088cSDongdong Hao starget_priv->deleted = 1;
34485597088cSDongdong Hao leapraid_ublk_io_dev(adapter,
34495597088cSDongdong Hao sas_dev->sas_addr, sas_dev->card_port);
34505597088cSDongdong Hao starget_priv->hdl = LEAPRAID_INVALID_DEV_HANDLE;
34515597088cSDongdong Hao }
34525597088cSDongdong Hao
34535597088cSDongdong Hao leapraid_transport_port_remove(adapter,
34545597088cSDongdong Hao sas_dev->sas_addr,
34555597088cSDongdong Hao sas_dev->parent_sas_addr,
34565597088cSDongdong Hao sas_dev->card_port);
34575597088cSDongdong Hao
34585597088cSDongdong Hao dev_info(&adapter->pdev->dev,
34595597088cSDongdong Hao "remove dev: hdl=0x%04x, SAS addr=0x%016llx\n",
34605597088cSDongdong Hao sas_dev->hdl, (unsigned long long)sas_dev->sas_addr);
34615597088cSDongdong Hao }
34625597088cSDongdong Hao
leapraid_alloc_vphy(struct leapraid_adapter * adapter,u8 port_id,u8 phy_num)34635597088cSDongdong Hao static struct leapraid_vphy *leapraid_alloc_vphy(
34645597088cSDongdong Hao struct leapraid_adapter *adapter,
34655597088cSDongdong Hao u8 port_id, u8 phy_num)
34665597088cSDongdong Hao {
34675597088cSDongdong Hao struct leapraid_card_port *port;
34685597088cSDongdong Hao struct leapraid_vphy *vphy;
34695597088cSDongdong Hao
34705597088cSDongdong Hao port = leapraid_get_port_by_id(adapter, port_id, false);
34715597088cSDongdong Hao if (!port)
34725597088cSDongdong Hao return NULL;
34735597088cSDongdong Hao
34745597088cSDongdong Hao vphy = leapraid_get_vphy_by_phy(port, phy_num);
34755597088cSDongdong Hao if (vphy)
34765597088cSDongdong Hao return vphy;
34775597088cSDongdong Hao vphy = kzalloc_obj(*vphy);
34785597088cSDongdong Hao if (!vphy)
34795597088cSDongdong Hao return NULL;
34805597088cSDongdong Hao
34815597088cSDongdong Hao if (!port->vphys_mask)
34825597088cSDongdong Hao INIT_LIST_HEAD(&port->vphys_list);
34835597088cSDongdong Hao
34845597088cSDongdong Hao port->vphys_mask |= BIT(phy_num);
34855597088cSDongdong Hao vphy->phy_mask |= BIT(phy_num);
34865597088cSDongdong Hao list_add_tail(&vphy->list, &port->vphys_list);
34875597088cSDongdong Hao return vphy;
34885597088cSDongdong Hao }
34895597088cSDongdong Hao
leapraid_add_port_to_card_port_list(struct leapraid_adapter * adapter,u8 port_id,bool refresh)34905597088cSDongdong Hao static int leapraid_add_port_to_card_port_list(
34915597088cSDongdong Hao struct leapraid_adapter *adapter,
34925597088cSDongdong Hao u8 port_id, bool refresh)
34935597088cSDongdong Hao {
34945597088cSDongdong Hao struct leapraid_card_port *card_port;
34955597088cSDongdong Hao
34965597088cSDongdong Hao card_port = leapraid_get_port_by_id(adapter, port_id, false);
34975597088cSDongdong Hao if (card_port)
34985597088cSDongdong Hao return 0;
34995597088cSDongdong Hao card_port = kzalloc_obj(*card_port);
35005597088cSDongdong Hao if (!card_port)
35015597088cSDongdong Hao return -ENOMEM;
35025597088cSDongdong Hao
35035597088cSDongdong Hao card_port->port_id = port_id;
35045597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
35055597088cSDongdong Hao "port: %d is added to card_port list\n",
35065597088cSDongdong Hao card_port->port_id);
35075597088cSDongdong Hao
35085597088cSDongdong Hao if (refresh && adapter->access_ctrl.shost_recovering)
35095597088cSDongdong Hao card_port->flg = LEAPRAID_CARD_PORT_FLG_NEW;
35105597088cSDongdong Hao list_add_tail(&card_port->list, &adapter->dev_topo.card_port_list);
35115597088cSDongdong Hao return 0;
35125597088cSDongdong Hao }
35135597088cSDongdong Hao
leapraid_add_card_phy(struct leapraid_adapter * adapter,struct leapraid_sas_io_unit_p0 * iou,int i)35145597088cSDongdong Hao static int leapraid_add_card_phy(struct leapraid_adapter *adapter,
35155597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *iou,
35165597088cSDongdong Hao int i)
35175597088cSDongdong Hao {
35185597088cSDongdong Hao struct leapraid_sas_phy_p0 phy_pg0;
35195597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
35205597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
35215597088cSDongdong Hao struct leapraid_topo_node *card = &adapter->dev_topo.card;
35225597088cSDongdong Hao u8 port_id;
35235597088cSDongdong Hao
35245597088cSDongdong Hao cfgp1.phy_number = i;
35255597088cSDongdong Hao
35265597088cSDongdong Hao if (leapraid_op_config_page(adapter, &phy_pg0,
35275597088cSDongdong Hao cfgp1, cfgp2, GET_PHY_PG0))
35285597088cSDongdong Hao return -EINVAL;
35295597088cSDongdong Hao
35305597088cSDongdong Hao port_id = iou->phy_info[i].port;
35315597088cSDongdong Hao
35325597088cSDongdong Hao if (leapraid_add_port_to_card_port_list(adapter, port_id, false))
35335597088cSDongdong Hao return -EINVAL;
35345597088cSDongdong Hao
35355597088cSDongdong Hao if ((le32_to_cpu(phy_pg0.phy_info) &
35365597088cSDongdong Hao LEAPRAID_SAS_PHYINFO_VPHY) &&
35375597088cSDongdong Hao ((phy_pg0.neg_link_rate >>
35385597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT) >=
35395597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5)) {
35405597088cSDongdong Hao if (!leapraid_alloc_vphy(adapter, port_id, i))
35415597088cSDongdong Hao return -ENOMEM;
35425597088cSDongdong Hao
35435597088cSDongdong Hao card->card_phy[i].vphy = 1;
35445597088cSDongdong Hao }
35455597088cSDongdong Hao
35465597088cSDongdong Hao card->card_phy[i].hdl = card->hdl;
35475597088cSDongdong Hao card->card_phy[i].phy_id = i;
35485597088cSDongdong Hao card->card_phy[i].card_port =
35495597088cSDongdong Hao leapraid_get_port_by_id(adapter, port_id, false);
35505597088cSDongdong Hao
35515597088cSDongdong Hao leapraid_transport_add_card_phy(adapter,
35525597088cSDongdong Hao &card->card_phy[i],
35535597088cSDongdong Hao &phy_pg0,
35545597088cSDongdong Hao card->parent_dev);
35555597088cSDongdong Hao
35565597088cSDongdong Hao return 0;
35575597088cSDongdong Hao }
35585597088cSDongdong Hao
leapraid_refresh_card_phy(struct leapraid_adapter * adapter,struct leapraid_sas_io_unit_p0 * iou,int i)35595597088cSDongdong Hao static int leapraid_refresh_card_phy(struct leapraid_adapter *adapter,
35605597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *iou,
35615597088cSDongdong Hao int i)
35625597088cSDongdong Hao {
35635597088cSDongdong Hao struct leapraid_topo_node *card = &adapter->dev_topo.card;
35645597088cSDongdong Hao struct leapraid_sas_phy_p0 phy_pg0;
35655597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
35665597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
35675597088cSDongdong Hao u16 attached_hdl;
35685597088cSDongdong Hao u32 dev_info;
35695597088cSDongdong Hao u8 link_rate;
35705597088cSDongdong Hao u8 port_id;
35715597088cSDongdong Hao
35725597088cSDongdong Hao link_rate = iou->phy_info[i].neg_link_rate >>
35735597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT;
35745597088cSDongdong Hao port_id = iou->phy_info[i].port;
35755597088cSDongdong Hao if (leapraid_add_port_to_card_port_list(adapter, port_id, true))
35765597088cSDongdong Hao return -EINVAL;
35775597088cSDongdong Hao
35785597088cSDongdong Hao dev_info = le32_to_cpu(iou->phy_info[i].controller_phy_dev_info);
35795597088cSDongdong Hao if (dev_info & LEAPRAID_DEVTYP_SEP &&
35805597088cSDongdong Hao link_rate >= LEAPRAID_SAS_NEG_LINK_RATE_1_5) {
35815597088cSDongdong Hao cfgp1.phy_number = i;
35825597088cSDongdong Hao
35835597088cSDongdong Hao if (leapraid_op_config_page(adapter, &phy_pg0,
35845597088cSDongdong Hao cfgp1, cfgp2, GET_PHY_PG0))
35855597088cSDongdong Hao return 0;
35865597088cSDongdong Hao
35875597088cSDongdong Hao if (le32_to_cpu(phy_pg0.phy_info) &
35885597088cSDongdong Hao LEAPRAID_SAS_PHYINFO_VPHY) {
35895597088cSDongdong Hao if (!leapraid_alloc_vphy(adapter, port_id, i))
35905597088cSDongdong Hao return -ENOMEM;
35915597088cSDongdong Hao card->card_phy[i].vphy = 1;
35925597088cSDongdong Hao }
35935597088cSDongdong Hao }
35945597088cSDongdong Hao
35955597088cSDongdong Hao card->card_phy[i].hdl = card->hdl;
35965597088cSDongdong Hao
35975597088cSDongdong Hao attached_hdl = le16_to_cpu(iou->phy_info[i].attached_dev_hdl);
35985597088cSDongdong Hao if (attached_hdl && link_rate < LEAPRAID_SAS_NEG_LINK_RATE_1_5)
35995597088cSDongdong Hao link_rate = LEAPRAID_SAS_NEG_LINK_RATE_1_5;
36005597088cSDongdong Hao
36015597088cSDongdong Hao card->card_phy[i].card_port =
36025597088cSDongdong Hao leapraid_get_port_by_id(adapter, port_id, false);
36035597088cSDongdong Hao
36045597088cSDongdong Hao if (!card->card_phy[i].phy) {
36055597088cSDongdong Hao cfgp1.phy_number = i;
36065597088cSDongdong Hao if (leapraid_op_config_page(adapter, &phy_pg0,
36075597088cSDongdong Hao cfgp1, cfgp2, GET_PHY_PG0))
36085597088cSDongdong Hao return 0;
36095597088cSDongdong Hao
36105597088cSDongdong Hao card->card_phy[i].phy_id = i;
36115597088cSDongdong Hao
36125597088cSDongdong Hao leapraid_transport_add_card_phy(adapter,
36135597088cSDongdong Hao &card->card_phy[i],
36145597088cSDongdong Hao &phy_pg0,
36155597088cSDongdong Hao card->parent_dev);
36165597088cSDongdong Hao return 0;
36175597088cSDongdong Hao }
36185597088cSDongdong Hao
36195597088cSDongdong Hao leapraid_transport_update_links(adapter,
36205597088cSDongdong Hao card->sas_address,
36215597088cSDongdong Hao attached_hdl,
36225597088cSDongdong Hao i,
36235597088cSDongdong Hao link_rate,
36245597088cSDongdong Hao card->card_phy[i].card_port);
36255597088cSDongdong Hao
36265597088cSDongdong Hao return 0;
36275597088cSDongdong Hao }
36285597088cSDongdong Hao
leapraid_sas_host_add(struct leapraid_adapter * adapter,bool refresh)36295597088cSDongdong Hao static void leapraid_sas_host_add(struct leapraid_adapter *adapter,
36305597088cSDongdong Hao bool refresh)
36315597088cSDongdong Hao {
36325597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
36335597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
36345597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_pg0;
36355597088cSDongdong Hao struct leapraid_enc_p0 enc_pg0;
36365597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_iou_pg0;
36375597088cSDongdong Hao u16 sas_iou_pg0_sz;
36385597088cSDongdong Hao u8 phys_num;
36395597088cSDongdong Hao int i;
36405597088cSDongdong Hao int rc;
36415597088cSDongdong Hao
36425597088cSDongdong Hao if (!refresh) {
36435597088cSDongdong Hao if (leapraid_get_adapter_phys(adapter, &phys_num) || !phys_num)
36445597088cSDongdong Hao return;
36455597088cSDongdong Hao
36465597088cSDongdong Hao adapter->dev_topo.card.card_phy =
36475597088cSDongdong Hao kcalloc(phys_num,
36485597088cSDongdong Hao sizeof(struct leapraid_card_phy), GFP_KERNEL);
36495597088cSDongdong Hao if (!adapter->dev_topo.card.card_phy)
36505597088cSDongdong Hao return;
36515597088cSDongdong Hao
36525597088cSDongdong Hao adapter->dev_topo.card.phys_num = phys_num;
36535597088cSDongdong Hao }
36545597088cSDongdong Hao
36555597088cSDongdong Hao sas_iou_pg0_sz =
36565597088cSDongdong Hao offsetof(struct leapraid_sas_io_unit_p0, phy_info) +
36575597088cSDongdong Hao (adapter->dev_topo.card.phys_num *
36585597088cSDongdong Hao sizeof(struct leapraid_sas_io_unit0_phy_info));
36595597088cSDongdong Hao sas_iou_pg0 = kzalloc(sas_iou_pg0_sz, GFP_KERNEL);
36605597088cSDongdong Hao if (!sas_iou_pg0)
36615597088cSDongdong Hao return;
36625597088cSDongdong Hao
36635597088cSDongdong Hao if (leapraid_get_sas_io_unit_page0(adapter,
36645597088cSDongdong Hao sas_iou_pg0,
36655597088cSDongdong Hao sas_iou_pg0_sz))
36665597088cSDongdong Hao goto out_free;
36675597088cSDongdong Hao
36685597088cSDongdong Hao adapter->dev_topo.card.parent_dev = &adapter->shost->shost_gendev;
36695597088cSDongdong Hao adapter->dev_topo.card.hdl =
36705597088cSDongdong Hao le16_to_cpu(sas_iou_pg0->phy_info[0].controller_dev_hdl);
36715597088cSDongdong Hao for (i = 0; i < adapter->dev_topo.card.phys_num; i++) {
36725597088cSDongdong Hao if (!refresh) /* add */
36735597088cSDongdong Hao rc = leapraid_add_card_phy(adapter, sas_iou_pg0, i);
36745597088cSDongdong Hao else /* refresh */
36755597088cSDongdong Hao rc = leapraid_refresh_card_phy(adapter,
36765597088cSDongdong Hao sas_iou_pg0,
36775597088cSDongdong Hao i);
36785597088cSDongdong Hao if (rc)
36795597088cSDongdong Hao goto out_free;
36805597088cSDongdong Hao }
36815597088cSDongdong Hao
36825597088cSDongdong Hao if (!refresh) {
36835597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
36845597088cSDongdong Hao cfgp2.handle = adapter->dev_topo.card.hdl;
36855597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_pg0, cfgp1,
36865597088cSDongdong Hao cfgp2, GET_SAS_DEVICE_PG0))
36875597088cSDongdong Hao goto out_free;
36885597088cSDongdong Hao
36895597088cSDongdong Hao adapter->dev_topo.card.enc_hdl =
36905597088cSDongdong Hao le16_to_cpu(sas_dev_pg0.enc_hdl);
36915597088cSDongdong Hao adapter->dev_topo.card.sas_address =
36925597088cSDongdong Hao le64_to_cpu(sas_dev_pg0.sas_address);
36935597088cSDongdong Hao dev_info(&adapter->pdev->dev,
36945597088cSDongdong Hao "add host: hdl=0x%04x, SAS addr=0x%016llx, phy=%d\n",
36955597088cSDongdong Hao adapter->dev_topo.card.hdl,
36965597088cSDongdong Hao (unsigned long long)adapter->dev_topo.card.sas_address,
36975597088cSDongdong Hao adapter->dev_topo.card.phys_num);
36985597088cSDongdong Hao
36995597088cSDongdong Hao if (adapter->dev_topo.card.enc_hdl) {
37005597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_ENC_CFG_PGAD_HDL;
37015597088cSDongdong Hao cfgp2.handle = adapter->dev_topo.card.enc_hdl;
37025597088cSDongdong Hao if (!(leapraid_op_config_page(adapter, &enc_pg0,
37035597088cSDongdong Hao cfgp1, cfgp2,
37045597088cSDongdong Hao GET_SAS_ENCLOSURE_PG0)))
37055597088cSDongdong Hao adapter->dev_topo.card.enc_lid =
37065597088cSDongdong Hao le64_to_cpu(enc_pg0.enc_lid);
37075597088cSDongdong Hao }
37085597088cSDongdong Hao }
37095597088cSDongdong Hao out_free:
37105597088cSDongdong Hao kfree(sas_iou_pg0);
37115597088cSDongdong Hao }
37125597088cSDongdong Hao
leapraid_internal_exp_add(struct leapraid_adapter * adapter,struct leapraid_exp_p0 * exp_pg0,union cfg_param_1 * cfgp1,union cfg_param_2 * cfgp2,u16 hdl)37135597088cSDongdong Hao static int leapraid_internal_exp_add(struct leapraid_adapter *adapter,
37145597088cSDongdong Hao struct leapraid_exp_p0 *exp_pg0,
37155597088cSDongdong Hao union cfg_param_1 *cfgp1,
37165597088cSDongdong Hao union cfg_param_2 *cfgp2,
37175597088cSDongdong Hao u16 hdl)
37185597088cSDongdong Hao {
37195597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
37205597088cSDongdong Hao struct leapraid_sas_port *sas_port = NULL;
37215597088cSDongdong Hao struct leapraid_enc_node *enc_dev;
37225597088cSDongdong Hao struct leapraid_exp_p1 exp_pg1;
37235597088cSDongdong Hao int ret;
37245597088cSDongdong Hao int rc;
37255597088cSDongdong Hao unsigned long flags;
37265597088cSDongdong Hao u8 port_id;
37275597088cSDongdong Hao u16 parent_handle;
37285597088cSDongdong Hao u64 sas_addr_parent;
37295597088cSDongdong Hao int i;
37305597088cSDongdong Hao
37315597088cSDongdong Hao port_id = exp_pg0->physical_port;
37325597088cSDongdong Hao parent_handle = le16_to_cpu(exp_pg0->parent_dev_hdl);
37335597088cSDongdong Hao
37345597088cSDongdong Hao rc = leapraid_get_sas_address(adapter,
37355597088cSDongdong Hao parent_handle, &sas_addr_parent);
37365597088cSDongdong Hao if (rc)
37375597088cSDongdong Hao return rc;
37385597088cSDongdong Hao topo_node_exp = kzalloc_obj(*topo_node_exp);
37395597088cSDongdong Hao if (!topo_node_exp)
37405597088cSDongdong Hao return -ENOMEM;
37415597088cSDongdong Hao
37425597088cSDongdong Hao topo_node_exp->hdl = hdl;
37435597088cSDongdong Hao topo_node_exp->phys_num = exp_pg0->phy_num;
37445597088cSDongdong Hao topo_node_exp->sas_address_parent = sas_addr_parent;
37455597088cSDongdong Hao topo_node_exp->sas_address = le64_to_cpu(exp_pg0->sas_address);
37465597088cSDongdong Hao topo_node_exp->card_port =
37475597088cSDongdong Hao leapraid_get_port_by_id(adapter, port_id, false);
37485597088cSDongdong Hao if (!topo_node_exp->card_port) {
37495597088cSDongdong Hao rc = -EPERM;
37505597088cSDongdong Hao goto out_fail;
37515597088cSDongdong Hao }
37525597088cSDongdong Hao
37535597088cSDongdong Hao dev_info(&adapter->pdev->dev,
37545597088cSDongdong Hao "add exp: saddr=0x%016llx, hdl=0x%04x, phdl=0x%04x, phy=%d\n",
37555597088cSDongdong Hao (unsigned long long)topo_node_exp->sas_address,
37565597088cSDongdong Hao hdl, parent_handle,
37575597088cSDongdong Hao topo_node_exp->phys_num);
37585597088cSDongdong Hao if (!topo_node_exp->phys_num) {
37595597088cSDongdong Hao dev_err(&adapter->pdev->dev,
37605597088cSDongdong Hao "%s: Invalid PHY num from exp_pg0\n", __func__);
37615597088cSDongdong Hao rc = -EPERM;
37625597088cSDongdong Hao goto out_fail;
37635597088cSDongdong Hao }
37645597088cSDongdong Hao
37655597088cSDongdong Hao topo_node_exp->card_phy =
37665597088cSDongdong Hao kcalloc(topo_node_exp->phys_num,
37675597088cSDongdong Hao sizeof(struct leapraid_card_phy), GFP_KERNEL);
37685597088cSDongdong Hao if (!topo_node_exp->card_phy) {
37695597088cSDongdong Hao dev_err(&adapter->pdev->dev,
37705597088cSDongdong Hao "%s: Failed to alloc expander phy array, count=%u\n",
37715597088cSDongdong Hao __func__, topo_node_exp->phys_num);
37725597088cSDongdong Hao rc = -EPERM;
37735597088cSDongdong Hao goto out_fail;
37745597088cSDongdong Hao }
37755597088cSDongdong Hao
37765597088cSDongdong Hao INIT_LIST_HEAD(&topo_node_exp->sas_port_list);
37775597088cSDongdong Hao sas_port = leapraid_transport_port_add(adapter, hdl, sas_addr_parent,
37785597088cSDongdong Hao topo_node_exp->card_port);
37795597088cSDongdong Hao if (!sas_port) {
37805597088cSDongdong Hao rc = -EPERM;
37815597088cSDongdong Hao goto out_fail;
37825597088cSDongdong Hao }
37835597088cSDongdong Hao
37845597088cSDongdong Hao topo_node_exp->parent_dev = &sas_port->rphy->dev;
37855597088cSDongdong Hao topo_node_exp->rphy = sas_port->rphy;
37865597088cSDongdong Hao for (i = 0; i < topo_node_exp->phys_num; i++) {
37875597088cSDongdong Hao cfgp1->phy_number = i;
37885597088cSDongdong Hao cfgp2->handle = hdl;
37895597088cSDongdong Hao if (leapraid_op_config_page(adapter, &exp_pg1, *cfgp1, *cfgp2,
37905597088cSDongdong Hao GET_SAS_EXPANDER_PG1)) {
37915597088cSDongdong Hao dev_err(&adapter->pdev->dev,
37925597088cSDongdong Hao "%s: Failed to get exp_pg1, phy=%d\n",
37935597088cSDongdong Hao __func__, i);
37945597088cSDongdong Hao rc = -EPERM;
37955597088cSDongdong Hao goto out_fail;
37965597088cSDongdong Hao }
37975597088cSDongdong Hao
37985597088cSDongdong Hao topo_node_exp->card_phy[i].hdl = hdl;
37995597088cSDongdong Hao topo_node_exp->card_phy[i].phy_id = i;
38005597088cSDongdong Hao topo_node_exp->card_phy[i].card_port =
38015597088cSDongdong Hao leapraid_get_port_by_id(adapter, port_id, false);
38025597088cSDongdong Hao ret = leapraid_transport_add_exp_phy(
38035597088cSDongdong Hao adapter,
38045597088cSDongdong Hao &topo_node_exp->card_phy[i],
38055597088cSDongdong Hao &exp_pg1,
38065597088cSDongdong Hao topo_node_exp->parent_dev);
38075597088cSDongdong Hao if (ret) {
38085597088cSDongdong Hao rc = -EPERM;
38095597088cSDongdong Hao goto out_fail;
38105597088cSDongdong Hao }
38115597088cSDongdong Hao }
38125597088cSDongdong Hao
38135597088cSDongdong Hao if (topo_node_exp->enc_hdl) {
38145597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
38155597088cSDongdong Hao enc_dev = leapraid_enc_find_by_hdl(adapter,
38165597088cSDongdong Hao topo_node_exp->enc_hdl);
38175597088cSDongdong Hao if (enc_dev)
38185597088cSDongdong Hao topo_node_exp->enc_lid =
38195597088cSDongdong Hao le64_to_cpu(enc_dev->pg0.enc_lid);
38205597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
38215597088cSDongdong Hao }
38225597088cSDongdong Hao
38235597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
38245597088cSDongdong Hao list_add_tail(&topo_node_exp->list, &adapter->dev_topo.exp_list);
38255597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
38265597088cSDongdong Hao return 0;
38275597088cSDongdong Hao
38285597088cSDongdong Hao out_fail:
38295597088cSDongdong Hao if (sas_port)
38305597088cSDongdong Hao leapraid_transport_port_remove(adapter,
38315597088cSDongdong Hao topo_node_exp->sas_address,
38325597088cSDongdong Hao sas_addr_parent,
38335597088cSDongdong Hao topo_node_exp->card_port);
38345597088cSDongdong Hao kfree(topo_node_exp->card_phy);
38355597088cSDongdong Hao kfree(topo_node_exp);
38365597088cSDongdong Hao return rc;
38375597088cSDongdong Hao }
38385597088cSDongdong Hao
leapraid_exp_add(struct leapraid_adapter * adapter,u16 hdl)38395597088cSDongdong Hao static int leapraid_exp_add(struct leapraid_adapter *adapter, u16 hdl)
38405597088cSDongdong Hao {
38415597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
38425597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
38435597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
38445597088cSDongdong Hao struct leapraid_exp_p0 exp_pg0;
38455597088cSDongdong Hao u16 parent_handle;
38465597088cSDongdong Hao u64 sas_addr, sas_addr_parent;
38475597088cSDongdong Hao unsigned long flags;
38485597088cSDongdong Hao u8 port_id;
38495597088cSDongdong Hao int rc;
38505597088cSDongdong Hao
38515597088cSDongdong Hao if (!hdl) {
38525597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "%s: Invalid hdl\n", __func__);
38535597088cSDongdong Hao return -EPERM;
38545597088cSDongdong Hao }
38555597088cSDongdong Hao
38565597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
38575597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) {
38585597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
38595597088cSDongdong Hao "%s: Failed, shost_recovering=%d pcie_recovering=%d\n",
38605597088cSDongdong Hao __func__, adapter->access_ctrl.shost_recovering,
38615597088cSDongdong Hao adapter->access_ctrl.pcie_recovering);
38625597088cSDongdong Hao return -EPERM;
38635597088cSDongdong Hao }
38645597088cSDongdong Hao
38655597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_EXP_CFD_PGAD_HDL;
38665597088cSDongdong Hao cfgp2.handle = hdl;
38675597088cSDongdong Hao if (leapraid_op_config_page(adapter, &exp_pg0, cfgp1, cfgp2,
38685597088cSDongdong Hao GET_SAS_EXPANDER_PG0))
38695597088cSDongdong Hao return -EPERM;
38705597088cSDongdong Hao
38715597088cSDongdong Hao parent_handle = le16_to_cpu(exp_pg0.parent_dev_hdl);
38725597088cSDongdong Hao if (leapraid_get_sas_address(adapter, parent_handle, &sas_addr_parent))
38735597088cSDongdong Hao return -EPERM;
38745597088cSDongdong Hao
38755597088cSDongdong Hao port_id = exp_pg0.physical_port;
38765597088cSDongdong Hao if (sas_addr_parent != adapter->dev_topo.card.sas_address) {
38775597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
38785597088cSDongdong Hao topo_node_exp =
38795597088cSDongdong Hao leapraid_exp_find_by_sas_address(
38805597088cSDongdong Hao adapter,
38815597088cSDongdong Hao sas_addr_parent,
38825597088cSDongdong Hao leapraid_get_port_by_id(adapter,
38835597088cSDongdong Hao port_id,
38845597088cSDongdong Hao false));
38855597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
38865597088cSDongdong Hao flags);
38875597088cSDongdong Hao if (!topo_node_exp) {
38885597088cSDongdong Hao rc = leapraid_exp_add(adapter, parent_handle);
38895597088cSDongdong Hao if (rc != 0)
38905597088cSDongdong Hao return rc;
38915597088cSDongdong Hao }
38925597088cSDongdong Hao }
38935597088cSDongdong Hao
38945597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
38955597088cSDongdong Hao sas_addr = le64_to_cpu(exp_pg0.sas_address);
38965597088cSDongdong Hao topo_node_exp =
38975597088cSDongdong Hao leapraid_exp_find_by_sas_address(
38985597088cSDongdong Hao adapter,
38995597088cSDongdong Hao sas_addr,
39005597088cSDongdong Hao leapraid_get_port_by_id(adapter, port_id, false));
39015597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
39025597088cSDongdong Hao
39035597088cSDongdong Hao if (topo_node_exp)
39045597088cSDongdong Hao return 0;
39055597088cSDongdong Hao
39065597088cSDongdong Hao return leapraid_internal_exp_add(adapter, &exp_pg0, &cfgp1,
39075597088cSDongdong Hao &cfgp2, hdl);
39085597088cSDongdong Hao }
39095597088cSDongdong Hao
leapraid_exp_node_rm(struct leapraid_adapter * adapter,struct leapraid_topo_node * topo_node_exp)39105597088cSDongdong Hao static void leapraid_exp_node_rm(struct leapraid_adapter *adapter,
39115597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp)
39125597088cSDongdong Hao {
39135597088cSDongdong Hao struct leapraid_sas_port *sas_port, *sas_port_next;
39145597088cSDongdong Hao unsigned long flags;
39155597088cSDongdong Hao int port_id;
39165597088cSDongdong Hao
39175597088cSDongdong Hao list_for_each_entry_safe(sas_port, sas_port_next,
39185597088cSDongdong Hao &topo_node_exp->sas_port_list,
39195597088cSDongdong Hao port_list) {
39205597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
39215597088cSDongdong Hao return;
39225597088cSDongdong Hao
39235597088cSDongdong Hao switch (sas_port->remote_identify.device_type) {
39245597088cSDongdong Hao case SAS_END_DEVICE:
39255597088cSDongdong Hao leapraid_sas_dev_remove_by_sas_address(
39265597088cSDongdong Hao adapter,
39275597088cSDongdong Hao sas_port->remote_identify.sas_address,
39285597088cSDongdong Hao sas_port->card_port);
39295597088cSDongdong Hao break;
39305597088cSDongdong Hao case SAS_EDGE_EXPANDER_DEVICE:
39315597088cSDongdong Hao case SAS_FANOUT_EXPANDER_DEVICE:
39325597088cSDongdong Hao leapraid_exp_rm(
39335597088cSDongdong Hao adapter,
39345597088cSDongdong Hao sas_port->remote_identify.sas_address,
39355597088cSDongdong Hao sas_port->card_port);
39365597088cSDongdong Hao break;
39375597088cSDongdong Hao default:
39385597088cSDongdong Hao break;
39395597088cSDongdong Hao }
39405597088cSDongdong Hao }
39415597088cSDongdong Hao
39425597088cSDongdong Hao port_id = topo_node_exp->card_port->port_id;
39435597088cSDongdong Hao leapraid_transport_port_remove(adapter, topo_node_exp->sas_address,
39445597088cSDongdong Hao topo_node_exp->sas_address_parent,
39455597088cSDongdong Hao topo_node_exp->card_port);
39465597088cSDongdong Hao dev_info(&adapter->pdev->dev,
39475597088cSDongdong Hao "removing exp: port=%d, SAS addr=0x%016llx, hdl=0x%04x\n",
39485597088cSDongdong Hao port_id, (unsigned long long)topo_node_exp->sas_address,
39495597088cSDongdong Hao topo_node_exp->hdl);
39505597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
39515597088cSDongdong Hao list_del(&topo_node_exp->list);
39525597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
39535597088cSDongdong Hao kfree(topo_node_exp->card_phy);
39545597088cSDongdong Hao kfree(topo_node_exp);
39555597088cSDongdong Hao }
39565597088cSDongdong Hao
leapraid_exp_rm(struct leapraid_adapter * adapter,u64 sas_addr,struct leapraid_card_port * port)39575597088cSDongdong Hao void leapraid_exp_rm(struct leapraid_adapter *adapter, u64 sas_addr,
39585597088cSDongdong Hao struct leapraid_card_port *port)
39595597088cSDongdong Hao {
39605597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
39615597088cSDongdong Hao unsigned long flags;
39625597088cSDongdong Hao
39635597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
39645597088cSDongdong Hao return;
39655597088cSDongdong Hao
39665597088cSDongdong Hao if (!port)
39675597088cSDongdong Hao return;
39685597088cSDongdong Hao
39695597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
39705597088cSDongdong Hao topo_node_exp = leapraid_exp_find_by_sas_address(adapter,
39715597088cSDongdong Hao sas_addr,
39725597088cSDongdong Hao port);
39735597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
39745597088cSDongdong Hao
39755597088cSDongdong Hao if (topo_node_exp)
39765597088cSDongdong Hao leapraid_exp_node_rm(adapter, topo_node_exp);
39775597088cSDongdong Hao }
39785597088cSDongdong Hao
leapraid_internal_sas_topo_chg_evt(struct leapraid_adapter * adapter,struct leapraid_card_port * card_port,struct leapraid_topo_node * topo_node_exp,struct leapraid_fw_evt_work * fw_evt,u64 sas_addr,u8 max_phys)39795597088cSDongdong Hao static void leapraid_internal_sas_topo_chg_evt(
39805597088cSDongdong Hao struct leapraid_adapter *adapter,
39815597088cSDongdong Hao struct leapraid_card_port *card_port,
39825597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp,
39835597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt,
39845597088cSDongdong Hao u64 sas_addr, u8 max_phys)
39855597088cSDongdong Hao {
39865597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *evt_data;
39875597088cSDongdong Hao u8 phy_number;
39885597088cSDongdong Hao u8 link_rate;
39895597088cSDongdong Hao u16 reason_code;
39905597088cSDongdong Hao u16 hdl;
39915597088cSDongdong Hao int i;
39925597088cSDongdong Hao
39935597088cSDongdong Hao evt_data = fw_evt->evt_data;
39945597088cSDongdong Hao for (i = 0; i < evt_data->entry_num; i++) {
39955597088cSDongdong Hao if (fw_evt->ignore)
39965597088cSDongdong Hao return;
39975597088cSDongdong Hao
39985597088cSDongdong Hao if (adapter->access_ctrl.host_removing ||
39995597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
40005597088cSDongdong Hao return;
40015597088cSDongdong Hao
40025597088cSDongdong Hao phy_number = evt_data->start_phy_num + i;
40035597088cSDongdong Hao if (phy_number >= max_phys)
40045597088cSDongdong Hao continue;
40055597088cSDongdong Hao
40065597088cSDongdong Hao reason_code = evt_data->phy[i].phy_status &
40075597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_RC_MASK;
40085597088cSDongdong Hao
40095597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phy[i].attached_dev_hdl);
40105597088cSDongdong Hao if (!hdl ||
40115597088cSDongdong Hao hdl > adapter->adapter_attr.features.max_dev_handle) {
40125597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
40135597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
40145597088cSDongdong Hao continue;
40155597088cSDongdong Hao }
40165597088cSDongdong Hao link_rate = evt_data->phy[i].link_rate >>
40175597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT;
40185597088cSDongdong Hao switch (reason_code) {
40195597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_RC_TARG_ADDED:
40205597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
40215597088cSDongdong Hao break;
40225597088cSDongdong Hao leapraid_transport_update_links(adapter, sas_addr,
40235597088cSDongdong Hao hdl, phy_number,
40245597088cSDongdong Hao link_rate, card_port);
40255597088cSDongdong Hao if (link_rate < LEAPRAID_SAS_NEG_LINK_RATE_1_5)
40265597088cSDongdong Hao break;
40275597088cSDongdong Hao leapraid_add_dev(adapter, hdl);
40285597088cSDongdong Hao break;
40295597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
40305597088cSDongdong Hao leapraid_sas_dev_remove_by_hdl(adapter, hdl);
40315597088cSDongdong Hao break;
40325597088cSDongdong Hao }
40335597088cSDongdong Hao }
40345597088cSDongdong Hao
40355597088cSDongdong Hao if (evt_data->exp_status == LEAPRAID_EVT_SAS_TOPO_ES_NOT_RESPONDING &&
40365597088cSDongdong Hao topo_node_exp)
40375597088cSDongdong Hao leapraid_exp_rm(adapter, sas_addr, card_port);
40385597088cSDongdong Hao }
40395597088cSDongdong Hao
leapraid_sas_topo_chg_evt(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)40405597088cSDongdong Hao static void leapraid_sas_topo_chg_evt(struct leapraid_adapter *adapter,
40415597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
40425597088cSDongdong Hao {
40435597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
40445597088cSDongdong Hao struct leapraid_card_port *card_port;
40455597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *evt_data;
40465597088cSDongdong Hao u16 phdl;
40475597088cSDongdong Hao u8 max_phys;
40485597088cSDongdong Hao u64 sas_addr;
40495597088cSDongdong Hao unsigned long flags;
40505597088cSDongdong Hao
40515597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
40525597088cSDongdong Hao adapter->access_ctrl.host_removing ||
40535597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
40545597088cSDongdong Hao return;
40555597088cSDongdong Hao
40565597088cSDongdong Hao evt_data = fw_evt->evt_data;
40575597088cSDongdong Hao leapraid_sas_host_add(adapter, adapter->dev_topo.card.phys_num > 0);
40585597088cSDongdong Hao
40595597088cSDongdong Hao if (fw_evt->ignore)
40605597088cSDongdong Hao return;
40615597088cSDongdong Hao
40625597088cSDongdong Hao phdl = le16_to_cpu(evt_data->exp_dev_hdl);
40635597088cSDongdong Hao card_port = leapraid_get_port_by_id(adapter,
40645597088cSDongdong Hao evt_data->physical_port,
40655597088cSDongdong Hao false);
40665597088cSDongdong Hao if (evt_data->exp_status == LEAPRAID_EVT_SAS_TOPO_ES_ADDED &&
40675597088cSDongdong Hao leapraid_exp_add(adapter, phdl) != 0)
40685597088cSDongdong Hao return;
40695597088cSDongdong Hao
40705597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
40715597088cSDongdong Hao topo_node_exp = leapraid_exp_find_by_hdl(adapter, phdl);
40725597088cSDongdong Hao if (topo_node_exp) {
40735597088cSDongdong Hao sas_addr = topo_node_exp->sas_address;
40745597088cSDongdong Hao max_phys = topo_node_exp->phys_num;
40755597088cSDongdong Hao card_port = topo_node_exp->card_port;
40765597088cSDongdong Hao } else if (phdl < adapter->dev_topo.card.phys_num) {
40775597088cSDongdong Hao sas_addr = adapter->dev_topo.card.sas_address;
40785597088cSDongdong Hao max_phys = adapter->dev_topo.card.phys_num;
40795597088cSDongdong Hao } else {
40805597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
40815597088cSDongdong Hao flags);
40825597088cSDongdong Hao return;
40835597088cSDongdong Hao }
40845597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
40855597088cSDongdong Hao
40865597088cSDongdong Hao leapraid_internal_sas_topo_chg_evt(adapter, card_port,
40875597088cSDongdong Hao topo_node_exp, fw_evt,
40885597088cSDongdong Hao sas_addr, max_phys);
40895597088cSDongdong Hao }
40905597088cSDongdong Hao
leapraid_reprobe_lun(struct scsi_device * sdev,void * no_uld_attach)40915597088cSDongdong Hao static void leapraid_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
40925597088cSDongdong Hao {
40935597088cSDongdong Hao sdev->no_uld_attach = no_uld_attach ? 1 : 0;
40945597088cSDongdong Hao sdev_printk(KERN_INFO, sdev,
40955597088cSDongdong Hao "%s RAID component to upper layer\n",
40965597088cSDongdong Hao sdev->no_uld_attach ? "hide" : "expose");
40975597088cSDongdong Hao WARN_ON(scsi_device_reprobe(sdev));
40985597088cSDongdong Hao }
40995597088cSDongdong Hao
leapraid_sas_pd_add(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)41005597088cSDongdong Hao static void leapraid_sas_pd_add(
41015597088cSDongdong Hao struct leapraid_adapter *adapter,
41025597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
41035597088cSDongdong Hao {
41045597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
41055597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
41065597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
41075597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
41085597088cSDongdong Hao u64 sas_address;
41095597088cSDongdong Hao u16 parent_hdl;
41105597088cSDongdong Hao u16 hdl;
41115597088cSDongdong Hao
41125597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phys_disk_dev_hdl);
41135597088cSDongdong Hao if (!hdl || hdl > adapter->adapter_attr.features.max_dev_handle) {
41145597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
41155597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
41165597088cSDongdong Hao return;
41175597088cSDongdong Hao }
41185597088cSDongdong Hao
41195597088cSDongdong Hao set_bit(hdl, adapter->dev_topo.pd_hdls);
41205597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_hdl(adapter, hdl);
41215597088cSDongdong Hao if (sas_dev) {
41225597088cSDongdong Hao leapraid_sdev_put(sas_dev);
41235597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
41245597088cSDongdong Hao "Dev handle 0x%x already exists\n", hdl);
41255597088cSDongdong Hao return;
41265597088cSDongdong Hao }
41275597088cSDongdong Hao
41285597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
41295597088cSDongdong Hao cfgp2.handle = hdl;
41305597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_p0, cfgp1, cfgp2,
41315597088cSDongdong Hao GET_SAS_DEVICE_PG0)) {
41325597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "Failed to read dev page0\n");
41335597088cSDongdong Hao return;
41345597088cSDongdong Hao }
41355597088cSDongdong Hao
41365597088cSDongdong Hao parent_hdl = le16_to_cpu(sas_dev_p0.parent_dev_hdl);
41375597088cSDongdong Hao if (!leapraid_get_sas_address(adapter, parent_hdl, &sas_address))
41385597088cSDongdong Hao leapraid_transport_update_links(adapter, sas_address, hdl,
41395597088cSDongdong Hao sas_dev_p0.phy_num,
41405597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5,
41415597088cSDongdong Hao leapraid_get_port_by_id(adapter,
41425597088cSDongdong Hao sas_dev_p0.physical_port,
41435597088cSDongdong Hao false));
41445597088cSDongdong Hao leapraid_add_dev(adapter, hdl);
41455597088cSDongdong Hao }
41465597088cSDongdong Hao
leapraid_sas_pd_delete(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)41475597088cSDongdong Hao static void leapraid_sas_pd_delete(
41485597088cSDongdong Hao struct leapraid_adapter *adapter,
41495597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
41505597088cSDongdong Hao {
41515597088cSDongdong Hao u16 hdl;
41525597088cSDongdong Hao
41535597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phys_disk_dev_hdl);
41545597088cSDongdong Hao leapraid_sas_dev_remove_by_hdl(adapter, hdl);
41555597088cSDongdong Hao }
41565597088cSDongdong Hao
leapraid_sas_pd_hide(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)41575597088cSDongdong Hao static void leapraid_sas_pd_hide(
41585597088cSDongdong Hao struct leapraid_adapter *adapter,
41595597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
41605597088cSDongdong Hao {
41615597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
41625597088cSDongdong Hao struct scsi_target *starget = NULL;
41635597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
41645597088cSDongdong Hao unsigned long flags;
41655597088cSDongdong Hao u64 volume_wwid = 0;
41665597088cSDongdong Hao u16 volume_hdl;
41675597088cSDongdong Hao u16 hdl;
41685597088cSDongdong Hao
41695597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phys_disk_dev_hdl);
41705597088cSDongdong Hao if (!hdl || hdl > adapter->adapter_attr.features.max_dev_handle) {
41715597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
41725597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
41735597088cSDongdong Hao return;
41745597088cSDongdong Hao }
41755597088cSDongdong Hao leapraid_cfg_get_volume_hdl(adapter, hdl, &volume_hdl);
41765597088cSDongdong Hao if (volume_hdl)
41775597088cSDongdong Hao leapraid_cfg_get_volume_wwid(adapter,
41785597088cSDongdong Hao volume_hdl,
41795597088cSDongdong Hao &volume_wwid);
41805597088cSDongdong Hao
41815597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
41825597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
41835597088cSDongdong Hao if (!sas_dev) {
41845597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
41855597088cSDongdong Hao return;
41865597088cSDongdong Hao }
41875597088cSDongdong Hao
41885597088cSDongdong Hao set_bit(hdl, adapter->dev_topo.pd_hdls);
41895597088cSDongdong Hao if (sas_dev->starget && sas_dev->starget->hostdata) {
41905597088cSDongdong Hao starget = sas_dev->starget;
41915597088cSDongdong Hao starget_priv = starget->hostdata;
41925597088cSDongdong Hao starget_priv->flg |= LEAPRAID_TGT_FLG_RAID_MEMBER;
41935597088cSDongdong Hao sas_dev->volume_hdl = volume_hdl;
41945597088cSDongdong Hao sas_dev->volume_wwid = volume_wwid;
41955597088cSDongdong Hao }
41965597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
41975597088cSDongdong Hao if (starget) {
41985597088cSDongdong Hao starget_for_each_device(starget,
41995597088cSDongdong Hao (void *)LEAPRAID_NO_ULD_ATTACH_FLAG,
42005597088cSDongdong Hao leapraid_reprobe_lun);
42015597088cSDongdong Hao }
42025597088cSDongdong Hao
42035597088cSDongdong Hao leapraid_sdev_put(sas_dev);
42045597088cSDongdong Hao }
42055597088cSDongdong Hao
leapraid_sas_pd_expose(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)42065597088cSDongdong Hao static void leapraid_sas_pd_expose(
42075597088cSDongdong Hao struct leapraid_adapter *adapter,
42085597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
42095597088cSDongdong Hao {
42105597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
42115597088cSDongdong Hao struct scsi_target *starget = NULL;
42125597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
42135597088cSDongdong Hao unsigned long flags;
42145597088cSDongdong Hao u16 hdl;
42155597088cSDongdong Hao
42165597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phys_disk_dev_hdl);
42175597088cSDongdong Hao if (!hdl || hdl > adapter->adapter_attr.features.max_dev_handle) {
42185597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
42195597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
42205597088cSDongdong Hao return;
42215597088cSDongdong Hao }
42225597088cSDongdong Hao
42235597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
42245597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_hdl(adapter, hdl);
42255597088cSDongdong Hao if (!sas_dev) {
42265597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
42275597088cSDongdong Hao "%s:%d: sas_dev not found, hdl=0x%x\n",
42285597088cSDongdong Hao __func__, __LINE__, hdl);
42295597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
42305597088cSDongdong Hao return;
42315597088cSDongdong Hao }
42325597088cSDongdong Hao
42335597088cSDongdong Hao sas_dev->volume_hdl = 0;
42345597088cSDongdong Hao sas_dev->volume_wwid = 0;
42355597088cSDongdong Hao clear_bit(hdl, adapter->dev_topo.pd_hdls);
42365597088cSDongdong Hao if (sas_dev->starget && sas_dev->starget->hostdata) {
42375597088cSDongdong Hao starget = sas_dev->starget;
42385597088cSDongdong Hao starget_priv = starget->hostdata;
42395597088cSDongdong Hao starget_priv->flg &= ~LEAPRAID_TGT_FLG_RAID_MEMBER;
42405597088cSDongdong Hao sas_dev->led_on = 0;
42415597088cSDongdong Hao }
42425597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
42435597088cSDongdong Hao
42445597088cSDongdong Hao if (starget) {
42455597088cSDongdong Hao starget_for_each_device(starget,
42465597088cSDongdong Hao NULL,
42475597088cSDongdong Hao leapraid_reprobe_lun);
42485597088cSDongdong Hao }
42495597088cSDongdong Hao
42505597088cSDongdong Hao leapraid_sdev_put(sas_dev);
42515597088cSDongdong Hao }
42525597088cSDongdong Hao
leapraid_sas_vol_visibility(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)42535597088cSDongdong Hao static void leapraid_sas_vol_visibility(
42545597088cSDongdong Hao struct leapraid_adapter *adapter,
42555597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
42565597088cSDongdong Hao {
42575597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
42585597088cSDongdong Hao struct scsi_device *sdev;
42595597088cSDongdong Hao bool reprobe_flg = false;
42605597088cSDongdong Hao bool sdev_held = false;
42615597088cSDongdong Hao unsigned long flags;
42625597088cSDongdong Hao u16 hdl;
42635597088cSDongdong Hao u8 rc;
42645597088cSDongdong Hao
42655597088cSDongdong Hao hdl = le16_to_cpu(evt_data->vol_dev_hdl);
42665597088cSDongdong Hao rc = evt_data->reason_code;
42675597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_hdl(adapter, hdl);
42685597088cSDongdong Hao if (!raid_volume) {
42695597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
42705597088cSDongdong Hao "%s:%d: Volume handle 0x%x not found\n",
42715597088cSDongdong Hao __func__, __LINE__, hdl);
42725597088cSDongdong Hao return;
42735597088cSDongdong Hao }
42745597088cSDongdong Hao
42755597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
42765597088cSDongdong Hao sdev = raid_volume->sdev;
42775597088cSDongdong Hao if (!sdev) {
42785597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
42795597088cSDongdong Hao flags);
42805597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
42815597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
42825597088cSDongdong Hao "%s:%d: Volume handle 0x%x has no sdev\n",
42835597088cSDongdong Hao __func__, __LINE__, hdl);
42845597088cSDongdong Hao return;
42855597088cSDongdong Hao }
42865597088cSDongdong Hao
42875597088cSDongdong Hao if (sdev->no_uld_attach &&
42885597088cSDongdong Hao rc == LEAPRAID_EVT_IR_RC_VOLUME_UNHIDE) {
42895597088cSDongdong Hao sdev->no_uld_attach = 0;
42905597088cSDongdong Hao reprobe_flg = true;
42915597088cSDongdong Hao } else if (!sdev->no_uld_attach &&
42925597088cSDongdong Hao rc == LEAPRAID_EVT_IR_RC_VOLUME_HIDE) {
42935597088cSDongdong Hao sdev->no_uld_attach = 1;
42945597088cSDongdong Hao reprobe_flg = true;
42955597088cSDongdong Hao }
42965597088cSDongdong Hao
42975597088cSDongdong Hao if (reprobe_flg && !scsi_device_get(sdev))
42985597088cSDongdong Hao sdev_held = true;
42995597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
43005597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
43015597088cSDongdong Hao
43025597088cSDongdong Hao if (!reprobe_flg) {
43035597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
43045597088cSDongdong Hao "%s:rc(0x%x): Request matches, skipping\n",
43055597088cSDongdong Hao __func__, rc);
43065597088cSDongdong Hao return;
43075597088cSDongdong Hao }
43085597088cSDongdong Hao
43095597088cSDongdong Hao if (!sdev_held) {
43105597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
43115597088cSDongdong Hao "%s: Failed to hold sdev for reprobe, hdl=0x%x\n",
43125597088cSDongdong Hao __func__, hdl);
43135597088cSDongdong Hao return;
43145597088cSDongdong Hao }
43155597088cSDongdong Hao
43165597088cSDongdong Hao if (sdev->no_uld_attach)
43175597088cSDongdong Hao sdev_printk(KERN_INFO, sdev, "hide vol\n");
43185597088cSDongdong Hao else
43195597088cSDongdong Hao sdev_printk(KERN_INFO, sdev, "unhide vol\n");
43205597088cSDongdong Hao
43215597088cSDongdong Hao WARN_ON(scsi_device_reprobe(sdev));
43225597088cSDongdong Hao scsi_device_put(sdev);
43235597088cSDongdong Hao }
43245597088cSDongdong Hao
leapraid_sas_volume_add(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)43255597088cSDongdong Hao static void leapraid_sas_volume_add(
43265597088cSDongdong Hao struct leapraid_adapter *adapter,
43275597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
43285597088cSDongdong Hao {
43295597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
43305597088cSDongdong Hao unsigned long flags;
43315597088cSDongdong Hao u64 wwid;
43325597088cSDongdong Hao u16 hdl;
43335597088cSDongdong Hao
43345597088cSDongdong Hao hdl = le16_to_cpu(evt_data->vol_dev_hdl);
43355597088cSDongdong Hao
43365597088cSDongdong Hao if (leapraid_cfg_get_volume_wwid(adapter, hdl, &wwid)) {
43375597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "Failed to read volume page1\n");
43385597088cSDongdong Hao return;
43395597088cSDongdong Hao }
43405597088cSDongdong Hao
43415597088cSDongdong Hao if (!wwid) {
43425597088cSDongdong Hao dev_warn(&adapter->pdev->dev, "Invalid WWID(handle=0x%x)\n",
43435597088cSDongdong Hao hdl);
43445597088cSDongdong Hao return;
43455597088cSDongdong Hao }
43465597088cSDongdong Hao
43475597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_wwid(adapter, wwid);
43485597088cSDongdong Hao if (raid_volume) {
43495597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
43505597088cSDongdong Hao "Volume handle 0x%x already exists\n", hdl);
43515597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
43525597088cSDongdong Hao return;
43535597088cSDongdong Hao }
43545597088cSDongdong Hao
43555597088cSDongdong Hao raid_volume = kzalloc(sizeof(*raid_volume), GFP_KERNEL);
43565597088cSDongdong Hao if (!raid_volume)
43575597088cSDongdong Hao return;
43585597088cSDongdong Hao
43595597088cSDongdong Hao INIT_LIST_HEAD(&raid_volume->list);
43605597088cSDongdong Hao kref_init(&raid_volume->refcnt);
43615597088cSDongdong Hao raid_volume->id = adapter->dev_topo.sas_id++;
43625597088cSDongdong Hao raid_volume->channel = RAID_CHANNEL;
43635597088cSDongdong Hao raid_volume->hdl = hdl;
43645597088cSDongdong Hao raid_volume->wwid = wwid;
43655597088cSDongdong Hao leapraid_raid_volume_add(adapter, raid_volume);
43665597088cSDongdong Hao if (!adapter->scan_dev_desc.wait_scan_dev_done) {
43675597088cSDongdong Hao if (scsi_add_device(adapter->shost, RAID_CHANNEL,
43685597088cSDongdong Hao raid_volume->id, 0))
43695597088cSDongdong Hao leapraid_raid_volume_remove(adapter, raid_volume);
43705597088cSDongdong Hao dev_info(&adapter->pdev->dev,
43715597088cSDongdong Hao "add RAID volume: hdl=0x%x, wwid=0x%llx\n", hdl, wwid);
43725597088cSDongdong Hao } else {
43735597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
43745597088cSDongdong Hao leapraid_check_boot_dev(adapter, raid_volume, RAID_CHANNEL);
43755597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
43765597088cSDongdong Hao flags);
43775597088cSDongdong Hao }
43785597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
43795597088cSDongdong Hao }
43805597088cSDongdong Hao
leapraid_sas_volume_delete_by_ptr(struct leapraid_adapter * adapter,struct leapraid_raid_volume * raid_volume)43815597088cSDongdong Hao static void leapraid_sas_volume_delete_by_ptr(
43825597088cSDongdong Hao struct leapraid_adapter *adapter,
43835597088cSDongdong Hao struct leapraid_raid_volume *raid_volume)
43845597088cSDongdong Hao {
43855597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
43865597088cSDongdong Hao struct scsi_target *starget = NULL;
43875597088cSDongdong Hao unsigned long flags;
43885597088cSDongdong Hao bool in_list;
43895597088cSDongdong Hao
43905597088cSDongdong Hao if (!raid_volume)
43915597088cSDongdong Hao return;
43925597088cSDongdong Hao
43935597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
43945597088cSDongdong Hao in_list = !list_empty(&raid_volume->list);
43955597088cSDongdong Hao if (in_list && raid_volume->starget) {
43965597088cSDongdong Hao starget = raid_volume->starget;
43975597088cSDongdong Hao starget_priv = starget->hostdata;
43985597088cSDongdong Hao if (starget_priv)
43995597088cSDongdong Hao starget_priv->deleted = 1;
44005597088cSDongdong Hao }
44015597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
44025597088cSDongdong Hao
44035597088cSDongdong Hao if (!in_list)
44045597088cSDongdong Hao return;
44055597088cSDongdong Hao
44065597088cSDongdong Hao dev_info(&adapter->pdev->dev,
44075597088cSDongdong Hao "delete RAID volume: hdl=0x%x, wwid=0x%llx\n",
44085597088cSDongdong Hao raid_volume->hdl, raid_volume->wwid);
44095597088cSDongdong Hao leapraid_raid_volume_remove(adapter, raid_volume);
44105597088cSDongdong Hao
44115597088cSDongdong Hao if (starget)
44125597088cSDongdong Hao scsi_remove_target(&starget->dev);
44135597088cSDongdong Hao }
44145597088cSDongdong Hao
leapraid_sas_volume_delete(struct leapraid_adapter * adapter,u16 hdl)44155597088cSDongdong Hao static void leapraid_sas_volume_delete(struct leapraid_adapter *adapter,
44165597088cSDongdong Hao u16 hdl)
44175597088cSDongdong Hao {
44185597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
44195597088cSDongdong Hao
44205597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_hdl(adapter, hdl);
44215597088cSDongdong Hao if (!raid_volume) {
44225597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
44235597088cSDongdong Hao "%s:%d: Volume handle 0x%x not found\n",
44245597088cSDongdong Hao __func__, __LINE__, hdl);
44255597088cSDongdong Hao return;
44265597088cSDongdong Hao }
44275597088cSDongdong Hao
44285597088cSDongdong Hao leapraid_sas_volume_delete_by_ptr(adapter, raid_volume);
44295597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
44305597088cSDongdong Hao }
44315597088cSDongdong Hao
leapraid_sas_ir_chg_evt(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)44325597088cSDongdong Hao static void leapraid_sas_ir_chg_evt(struct leapraid_adapter *adapter,
44335597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
44345597088cSDongdong Hao {
44355597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data;
44365597088cSDongdong Hao
44375597088cSDongdong Hao evt_data = fw_evt->evt_data;
44385597088cSDongdong Hao
44395597088cSDongdong Hao switch (evt_data->reason_code) {
44405597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_VOLUME_ADD:
44415597088cSDongdong Hao leapraid_sas_volume_add(adapter, evt_data);
44425597088cSDongdong Hao break;
44435597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_VOLUME_DELETE:
44445597088cSDongdong Hao leapraid_sas_volume_delete(adapter,
44455597088cSDongdong Hao le16_to_cpu(evt_data->vol_dev_hdl));
44465597088cSDongdong Hao break;
44475597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_PD_HIDDEN_TO_ADD:
44485597088cSDongdong Hao leapraid_sas_pd_add(adapter, evt_data);
44495597088cSDongdong Hao break;
44505597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_PD_UNHIDDEN_TO_DELETE:
44515597088cSDongdong Hao leapraid_sas_pd_delete(adapter, evt_data);
44525597088cSDongdong Hao break;
44535597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_PD_CREATED_TO_HIDE:
44545597088cSDongdong Hao leapraid_sas_pd_hide(adapter, evt_data);
44555597088cSDongdong Hao break;
44565597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_PD_DELETED_TO_EXPOSE:
44575597088cSDongdong Hao leapraid_sas_pd_expose(adapter, evt_data);
44585597088cSDongdong Hao break;
44595597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_VOLUME_HIDE:
44605597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_VOLUME_UNHIDE:
44615597088cSDongdong Hao leapraid_sas_vol_visibility(adapter, evt_data);
44625597088cSDongdong Hao break;
44635597088cSDongdong Hao default:
44645597088cSDongdong Hao break;
44655597088cSDongdong Hao }
44665597088cSDongdong Hao }
44675597088cSDongdong Hao
leapraid_sas_enc_dev_stat_add_node(struct leapraid_adapter * adapter,u16 hdl)44685597088cSDongdong Hao static void leapraid_sas_enc_dev_stat_add_node(
44695597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
44705597088cSDongdong Hao {
44715597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
44725597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
44735597088cSDongdong Hao struct leapraid_enc_node *enc_node;
44745597088cSDongdong Hao struct leapraid_enc_node *enc_exist;
44755597088cSDongdong Hao unsigned long flags;
44765597088cSDongdong Hao int rc;
44775597088cSDongdong Hao
44785597088cSDongdong Hao enc_node = kzalloc_obj(*enc_node);
44795597088cSDongdong Hao if (!enc_node)
44805597088cSDongdong Hao return;
44815597088cSDongdong Hao
44825597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_ENC_CFG_PGAD_HDL;
44835597088cSDongdong Hao cfgp2.handle = hdl;
44845597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &enc_node->pg0, cfgp1, cfgp2,
44855597088cSDongdong Hao GET_SAS_ENCLOSURE_PG0);
44865597088cSDongdong Hao if (rc) {
44875597088cSDongdong Hao kfree(enc_node);
44885597088cSDongdong Hao return;
44895597088cSDongdong Hao }
44905597088cSDongdong Hao
44915597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
44925597088cSDongdong Hao enc_exist = leapraid_enc_find_by_hdl(adapter, hdl);
44935597088cSDongdong Hao if (enc_exist) {
44945597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
44955597088cSDongdong Hao kfree(enc_node);
44965597088cSDongdong Hao return;
44975597088cSDongdong Hao }
44985597088cSDongdong Hao list_add_tail(&enc_node->list, &adapter->dev_topo.enc_list);
44995597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
45005597088cSDongdong Hao }
45015597088cSDongdong Hao
leapraid_sas_enc_dev_stat_del_node(struct leapraid_adapter * adapter,u16 hdl)45025597088cSDongdong Hao static void leapraid_sas_enc_dev_stat_del_node(
45035597088cSDongdong Hao struct leapraid_adapter *adapter, u16 hdl)
45045597088cSDongdong Hao {
45055597088cSDongdong Hao struct leapraid_enc_node *enc_node;
45065597088cSDongdong Hao unsigned long flags;
45075597088cSDongdong Hao
45085597088cSDongdong Hao if (!hdl)
45095597088cSDongdong Hao return;
45105597088cSDongdong Hao
45115597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
45125597088cSDongdong Hao enc_node = leapraid_enc_find_by_hdl(adapter, hdl);
45135597088cSDongdong Hao if (enc_node)
45145597088cSDongdong Hao list_del(&enc_node->list);
45155597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
45165597088cSDongdong Hao
45175597088cSDongdong Hao kfree(enc_node);
45185597088cSDongdong Hao }
45195597088cSDongdong Hao
leapraid_sas_enc_dev_stat_chg_evt(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)45205597088cSDongdong Hao static void leapraid_sas_enc_dev_stat_chg_evt(
45215597088cSDongdong Hao struct leapraid_adapter *adapter,
45225597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
45235597088cSDongdong Hao {
45245597088cSDongdong Hao struct leapraid_evt_data_sas_enc_dev_status_change *evt_data;
45255597088cSDongdong Hao u16 enc_hdl;
45265597088cSDongdong Hao
45275597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering)
45285597088cSDongdong Hao return;
45295597088cSDongdong Hao
45305597088cSDongdong Hao evt_data = fw_evt->evt_data;
45315597088cSDongdong Hao enc_hdl = le16_to_cpu(evt_data->enc_hdl);
45325597088cSDongdong Hao switch (evt_data->reason_code) {
45335597088cSDongdong Hao case LEAPRAID_EVT_SAS_ENCL_RC_ADDED:
45345597088cSDongdong Hao if (enc_hdl)
45355597088cSDongdong Hao leapraid_sas_enc_dev_stat_add_node(adapter, enc_hdl);
45365597088cSDongdong Hao break;
45375597088cSDongdong Hao case LEAPRAID_EVT_SAS_ENCL_RC_NOT_RESPONDING:
45385597088cSDongdong Hao leapraid_sas_enc_dev_stat_del_node(adapter, enc_hdl);
45395597088cSDongdong Hao break;
45405597088cSDongdong Hao default:
45415597088cSDongdong Hao break;
45425597088cSDongdong Hao }
45435597088cSDongdong Hao }
45445597088cSDongdong Hao
leapraid_remove_unresp_sas_end_dev(struct leapraid_adapter * adapter)45455597088cSDongdong Hao static void leapraid_remove_unresp_sas_end_dev(
45465597088cSDongdong Hao struct leapraid_adapter *adapter)
45475597088cSDongdong Hao {
45485597088cSDongdong Hao struct leapraid_sas_dev *sas_dev, *sas_dev_next;
45495597088cSDongdong Hao unsigned long flags;
45505597088cSDongdong Hao LIST_HEAD(head);
45515597088cSDongdong Hao
45525597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
45535597088cSDongdong Hao list_for_each_entry_safe(sas_dev, sas_dev_next,
45545597088cSDongdong Hao &adapter->dev_topo.sas_dev_init_list, list) {
45555597088cSDongdong Hao if (sas_dev->rphy || sas_dev->pend_sas_rphy_add)
45565597088cSDongdong Hao continue;
45575597088cSDongdong Hao
45585597088cSDongdong Hao list_del_init(&sas_dev->list);
45595597088cSDongdong Hao leapraid_clear_cached_boot_dev(adapter, sas_dev, 0);
45605597088cSDongdong Hao leapraid_sdev_put(sas_dev);
45615597088cSDongdong Hao }
45625597088cSDongdong Hao list_for_each_entry_safe(sas_dev, sas_dev_next,
45635597088cSDongdong Hao &adapter->dev_topo.sas_dev_list, list) {
45645597088cSDongdong Hao if (!sas_dev->resp)
45655597088cSDongdong Hao list_move_tail(&sas_dev->list, &head);
45665597088cSDongdong Hao else
45675597088cSDongdong Hao sas_dev->resp = 0;
45685597088cSDongdong Hao }
45695597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
45705597088cSDongdong Hao
45715597088cSDongdong Hao list_for_each_entry_safe(sas_dev, sas_dev_next, &head, list) {
45725597088cSDongdong Hao leapraid_remove_device(adapter, sas_dev);
45735597088cSDongdong Hao list_del_init(&sas_dev->list);
45745597088cSDongdong Hao leapraid_sdev_put(sas_dev);
45755597088cSDongdong Hao }
45765597088cSDongdong Hao
45775597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
45785597088cSDongdong Hao "Unresponsive SAS end devices removed\n");
45795597088cSDongdong Hao }
45805597088cSDongdong Hao
leapraid_remove_unresp_raid_volumes(struct leapraid_adapter * adapter)45815597088cSDongdong Hao static void leapraid_remove_unresp_raid_volumes(
45825597088cSDongdong Hao struct leapraid_adapter *adapter)
45835597088cSDongdong Hao {
45845597088cSDongdong Hao unsigned long flags;
45855597088cSDongdong Hao struct leapraid_raid_volume *raid_volume, *raid_volume_next;
45865597088cSDongdong Hao LIST_HEAD(head);
45875597088cSDongdong Hao
45885597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
45895597088cSDongdong Hao list_for_each_entry_safe(raid_volume, raid_volume_next,
45905597088cSDongdong Hao &adapter->dev_topo.raid_volume_list, list) {
45915597088cSDongdong Hao if (!raid_volume->resp)
45925597088cSDongdong Hao list_move_tail(&raid_volume->list, &head);
45935597088cSDongdong Hao else
45945597088cSDongdong Hao raid_volume->resp = 0;
45955597088cSDongdong Hao }
45965597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
45975597088cSDongdong Hao
45985597088cSDongdong Hao list_for_each_entry_safe(raid_volume, raid_volume_next, &head, list) {
45995597088cSDongdong Hao leapraid_sas_volume_delete_by_ptr(adapter, raid_volume);
46005597088cSDongdong Hao }
46015597088cSDongdong Hao
46025597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
46035597088cSDongdong Hao "Unresponsive RAID volumes removed\n");
46045597088cSDongdong Hao }
46055597088cSDongdong Hao
leapraid_remove_unresp_sas_exp(struct leapraid_adapter * adapter)46065597088cSDongdong Hao static void leapraid_remove_unresp_sas_exp(struct leapraid_adapter *adapter)
46075597088cSDongdong Hao {
46085597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp, *topo_node_exp_next;
46095597088cSDongdong Hao unsigned long flags;
46105597088cSDongdong Hao LIST_HEAD(head);
46115597088cSDongdong Hao
46125597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
46135597088cSDongdong Hao list_for_each_entry_safe(topo_node_exp, topo_node_exp_next,
46145597088cSDongdong Hao &adapter->dev_topo.exp_list, list) {
46155597088cSDongdong Hao if (!topo_node_exp->resp)
46165597088cSDongdong Hao list_move_tail(&topo_node_exp->list, &head);
46175597088cSDongdong Hao else
46185597088cSDongdong Hao topo_node_exp->resp = 0;
46195597088cSDongdong Hao }
46205597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
46215597088cSDongdong Hao
46225597088cSDongdong Hao list_for_each_entry_safe(topo_node_exp, topo_node_exp_next,
46235597088cSDongdong Hao &head, list)
46245597088cSDongdong Hao leapraid_exp_node_rm(adapter, topo_node_exp);
46255597088cSDongdong Hao
46265597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
46275597088cSDongdong Hao "Unresponsive SAS expanders removed\n");
46285597088cSDongdong Hao }
46295597088cSDongdong Hao
leapraid_remove_unresp_dev(struct leapraid_adapter * adapter)46305597088cSDongdong Hao static void leapraid_remove_unresp_dev(struct leapraid_adapter *adapter)
46315597088cSDongdong Hao {
46325597088cSDongdong Hao leapraid_remove_unresp_sas_end_dev(adapter);
46335597088cSDongdong Hao if (adapter->adapter_attr.raid_support)
46345597088cSDongdong Hao leapraid_remove_unresp_raid_volumes(adapter);
46355597088cSDongdong Hao leapraid_remove_unresp_sas_exp(adapter);
46365597088cSDongdong Hao leapraid_ublk_io_all_dev(adapter);
46375597088cSDongdong Hao }
46385597088cSDongdong Hao
leapraid_del_dirty_vphy(struct leapraid_adapter * adapter)46395597088cSDongdong Hao static void leapraid_del_dirty_vphy(struct leapraid_adapter *adapter)
46405597088cSDongdong Hao {
46415597088cSDongdong Hao struct leapraid_card_port *card_port, *card_port_next;
46425597088cSDongdong Hao struct leapraid_vphy *vphy, *vphy_next;
46435597088cSDongdong Hao
46445597088cSDongdong Hao list_for_each_entry_safe(card_port, card_port_next,
46455597088cSDongdong Hao &adapter->dev_topo.card_port_list, list) {
46465597088cSDongdong Hao if (!card_port->vphys_mask)
46475597088cSDongdong Hao continue;
46485597088cSDongdong Hao
46495597088cSDongdong Hao list_for_each_entry_safe(vphy, vphy_next,
46505597088cSDongdong Hao &card_port->vphys_list, list) {
46515597088cSDongdong Hao if (!(vphy->flg & LEAPRAID_VPHY_FLG_DIRTY))
46525597088cSDongdong Hao continue;
46535597088cSDongdong Hao
46545597088cSDongdong Hao card_port->vphys_mask &= ~vphy->phy_mask;
46555597088cSDongdong Hao list_del(&vphy->list);
46565597088cSDongdong Hao kfree(vphy);
46575597088cSDongdong Hao }
46585597088cSDongdong Hao
46595597088cSDongdong Hao if (!card_port->vphys_mask && !card_port->sas_address)
46605597088cSDongdong Hao card_port->flg |= LEAPRAID_CARD_PORT_FLG_DIRTY;
46615597088cSDongdong Hao }
46625597088cSDongdong Hao }
46635597088cSDongdong Hao
leapraid_del_dirty_card_port(struct leapraid_adapter * adapter)46645597088cSDongdong Hao static void leapraid_del_dirty_card_port(struct leapraid_adapter *adapter)
46655597088cSDongdong Hao {
46665597088cSDongdong Hao struct leapraid_card_port *card_port, *card_port_next;
46675597088cSDongdong Hao
46685597088cSDongdong Hao list_for_each_entry_safe(card_port, card_port_next,
46695597088cSDongdong Hao &adapter->dev_topo.card_port_list, list) {
46705597088cSDongdong Hao if (!(card_port->flg & LEAPRAID_CARD_PORT_FLG_DIRTY) ||
46715597088cSDongdong Hao card_port->flg & LEAPRAID_CARD_PORT_FLG_NEW)
46725597088cSDongdong Hao continue;
46735597088cSDongdong Hao
46745597088cSDongdong Hao list_del(&card_port->list);
46755597088cSDongdong Hao kfree(card_port);
46765597088cSDongdong Hao }
46775597088cSDongdong Hao }
46785597088cSDongdong Hao
leapraid_update_dev_qdepth(struct leapraid_adapter * adapter)46795597088cSDongdong Hao static void leapraid_update_dev_qdepth(struct leapraid_adapter *adapter)
46805597088cSDongdong Hao {
46815597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
46825597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
46835597088cSDongdong Hao struct leapraid_adapter_attr *attr;
46845597088cSDongdong Hao struct scsi_device *sdev;
46855597088cSDongdong Hao u16 qdepth;
46865597088cSDongdong Hao
46875597088cSDongdong Hao attr = &adapter->adapter_attr;
46885597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
46895597088cSDongdong Hao sdev_priv = sdev->hostdata;
46905597088cSDongdong Hao if (!sdev_priv || !sdev_priv->starget_priv)
46915597088cSDongdong Hao continue;
46925597088cSDongdong Hao sas_dev = sdev_priv->starget_priv->sas_dev;
46935597088cSDongdong Hao if (sas_dev && sas_dev->dev_info & LEAPRAID_DEVTYP_SSP_TGT)
46945597088cSDongdong Hao qdepth = (sas_dev->port_connection > 1) ?
46955597088cSDongdong Hao attr->wideport_max_queue_depth :
46965597088cSDongdong Hao attr->narrowport_max_queue_depth;
46975597088cSDongdong Hao else if (sas_dev && sas_dev->dev_info &
46985597088cSDongdong Hao LEAPRAID_DEVTYP_SATA_DEV)
46995597088cSDongdong Hao qdepth = attr->sata_max_queue_depth;
47005597088cSDongdong Hao else
47015597088cSDongdong Hao continue;
47025597088cSDongdong Hao
47035597088cSDongdong Hao leapraid_change_queue_depth(sdev, qdepth);
47045597088cSDongdong Hao }
47055597088cSDongdong Hao }
47065597088cSDongdong Hao
leapraid_update_exp_links(struct leapraid_adapter * adapter,struct leapraid_topo_node * topo_node_exp,u16 hdl)47075597088cSDongdong Hao static void leapraid_update_exp_links(struct leapraid_adapter *adapter,
47085597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp,
47095597088cSDongdong Hao u16 hdl)
47105597088cSDongdong Hao {
47115597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
47125597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
47135597088cSDongdong Hao struct leapraid_exp_p1 exp_p1;
47145597088cSDongdong Hao int i;
47155597088cSDongdong Hao
47165597088cSDongdong Hao cfgp2.handle = hdl;
47175597088cSDongdong Hao for (i = 0; i < topo_node_exp->phys_num; i++) {
47185597088cSDongdong Hao cfgp1.phy_number = i;
47195597088cSDongdong Hao if (leapraid_op_config_page(adapter, &exp_p1, cfgp1, cfgp2,
47205597088cSDongdong Hao GET_SAS_EXPANDER_PG1))
47215597088cSDongdong Hao return;
47225597088cSDongdong Hao
47235597088cSDongdong Hao leapraid_transport_update_links(
47245597088cSDongdong Hao adapter,
47255597088cSDongdong Hao topo_node_exp->sas_address,
47265597088cSDongdong Hao le16_to_cpu(exp_p1.attached_dev_hdl),
47275597088cSDongdong Hao i,
47285597088cSDongdong Hao exp_p1.neg_link_rate >>
47295597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT,
47305597088cSDongdong Hao topo_node_exp->card_port);
47315597088cSDongdong Hao }
47325597088cSDongdong Hao }
47335597088cSDongdong Hao
leapraid_scan_exp_after_reset(struct leapraid_adapter * adapter)47345597088cSDongdong Hao static void leapraid_scan_exp_after_reset(struct leapraid_adapter *adapter)
47355597088cSDongdong Hao {
47365597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
47375597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
47385597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
47395597088cSDongdong Hao struct leapraid_exp_p0 exp_p0;
47405597088cSDongdong Hao unsigned long flags;
47415597088cSDongdong Hao u16 hdl;
47425597088cSDongdong Hao u8 port_id;
47435597088cSDongdong Hao
47445597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
47455597088cSDongdong Hao for (hdl = 0xFFFF, cfgp2.handle = hdl;
47465597088cSDongdong Hao !leapraid_op_config_page(adapter, &exp_p0, cfgp1, cfgp2,
47475597088cSDongdong Hao GET_SAS_EXPANDER_PG0);
47485597088cSDongdong Hao cfgp2.handle = hdl) {
47495597088cSDongdong Hao hdl = le16_to_cpu(exp_p0.dev_hdl);
47505597088cSDongdong Hao port_id = exp_p0.physical_port;
47515597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
47525597088cSDongdong Hao topo_node_exp =
47535597088cSDongdong Hao leapraid_exp_find_by_sas_address(
47545597088cSDongdong Hao adapter,
47555597088cSDongdong Hao le64_to_cpu(exp_p0.sas_address),
47565597088cSDongdong Hao leapraid_get_port_by_id(adapter,
47575597088cSDongdong Hao port_id,
47585597088cSDongdong Hao false));
47595597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
47605597088cSDongdong Hao flags);
47615597088cSDongdong Hao
47625597088cSDongdong Hao if (topo_node_exp) {
47635597088cSDongdong Hao leapraid_update_exp_links(adapter, topo_node_exp, hdl);
47645597088cSDongdong Hao } else {
47655597088cSDongdong Hao leapraid_exp_add(adapter, hdl);
47665597088cSDongdong Hao
47675597088cSDongdong Hao dev_info(&adapter->pdev->dev,
47685597088cSDongdong Hao "add exp: hdl=0x%04x, SAS addr=0x%016llx\n",
47695597088cSDongdong Hao hdl,
47705597088cSDongdong Hao (unsigned long long)le64_to_cpu(
47715597088cSDongdong Hao exp_p0.sas_address));
47725597088cSDongdong Hao }
47735597088cSDongdong Hao }
47745597088cSDongdong Hao }
47755597088cSDongdong Hao
leapraid_scan_phy_disks_after_reset(struct leapraid_adapter * adapter)47765597088cSDongdong Hao static void leapraid_scan_phy_disks_after_reset(
47775597088cSDongdong Hao struct leapraid_adapter *adapter)
47785597088cSDongdong Hao {
47795597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
47805597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
47815597088cSDongdong Hao union cfg_param_1 cfgp1_extra = {0};
47825597088cSDongdong Hao union cfg_param_2 cfgp2_extra = {0};
47835597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
47845597088cSDongdong Hao struct leapraid_raidpd_p0 raidpd_p0;
47855597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
47865597088cSDongdong Hao u8 phys_disk_num, port_id;
47875597088cSDongdong Hao u16 hdl, parent_hdl;
47885597088cSDongdong Hao u64 sas_addr;
47895597088cSDongdong Hao
47905597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
47915597088cSDongdong Hao for (phys_disk_num = 0xFF, cfgp2.form_specific = phys_disk_num;
47925597088cSDongdong Hao !leapraid_op_config_page(adapter, &raidpd_p0,
47935597088cSDongdong Hao cfgp1, cfgp2, GET_PHY_DISK_PG0);
47945597088cSDongdong Hao cfgp2.form_specific = phys_disk_num) {
47955597088cSDongdong Hao phys_disk_num = raidpd_p0.phys_disk_num;
47965597088cSDongdong Hao hdl = le16_to_cpu(raidpd_p0.dev_hdl);
47975597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_hdl(adapter, hdl);
47985597088cSDongdong Hao if (sas_dev) {
47995597088cSDongdong Hao leapraid_sdev_put(sas_dev);
48005597088cSDongdong Hao continue;
48015597088cSDongdong Hao }
48025597088cSDongdong Hao
48035597088cSDongdong Hao cfgp1_extra.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
48045597088cSDongdong Hao cfgp2_extra.handle = hdl;
48055597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_p0, cfgp1_extra,
48065597088cSDongdong Hao cfgp2_extra, GET_SAS_DEVICE_PG0) !=
48075597088cSDongdong Hao 0)
48085597088cSDongdong Hao continue;
48095597088cSDongdong Hao
48105597088cSDongdong Hao parent_hdl = le16_to_cpu(sas_dev_p0.parent_dev_hdl);
48115597088cSDongdong Hao if (!leapraid_get_sas_address(adapter,
48125597088cSDongdong Hao parent_hdl,
48135597088cSDongdong Hao &sas_addr)) {
48145597088cSDongdong Hao port_id = sas_dev_p0.physical_port;
48155597088cSDongdong Hao leapraid_transport_update_links(
48165597088cSDongdong Hao adapter, sas_addr, hdl,
48175597088cSDongdong Hao sas_dev_p0.phy_num,
48185597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5,
48195597088cSDongdong Hao leapraid_get_port_by_id(
48205597088cSDongdong Hao adapter, port_id, false));
48215597088cSDongdong Hao if (!hdl || hdl >
48225597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle) {
48235597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
48245597088cSDongdong Hao "%s: Invalid device handle\n",
48255597088cSDongdong Hao __func__);
48265597088cSDongdong Hao } else {
48275597088cSDongdong Hao set_bit(hdl, adapter->dev_topo.pd_hdls);
48285597088cSDongdong Hao leapraid_add_dev(adapter, hdl);
48295597088cSDongdong Hao
48305597088cSDongdong Hao dev_info(&adapter->pdev->dev,
48315597088cSDongdong Hao "add pd hdl=0x%04x saddr=0x%016llx\n",
48325597088cSDongdong Hao hdl,
48335597088cSDongdong Hao (unsigned long long)le64_to_cpu(
48345597088cSDongdong Hao sas_dev_p0.sas_address));
48355597088cSDongdong Hao }
48365597088cSDongdong Hao }
48375597088cSDongdong Hao }
48385597088cSDongdong Hao }
48395597088cSDongdong Hao
leapraid_scan_vol_after_reset(struct leapraid_adapter * adapter)48405597088cSDongdong Hao static void leapraid_scan_vol_after_reset(struct leapraid_adapter *adapter)
48415597088cSDongdong Hao {
48425597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
48435597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
48445597088cSDongdong Hao union cfg_param_1 cfgp1_extra = {0};
48455597088cSDongdong Hao union cfg_param_2 cfgp2_extra = {0};
48465597088cSDongdong Hao struct leapraid_evt_data_ir_change evt_data;
48475597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
48485597088cSDongdong Hao struct leapraid_raidvol_p1 *vol_p1;
48495597088cSDongdong Hao struct leapraid_raidvol_p0 *vol_p0;
48505597088cSDongdong Hao u16 hdl;
48515597088cSDongdong Hao
48525597088cSDongdong Hao vol_p0 = kzalloc_obj(*vol_p0);
48535597088cSDongdong Hao if (!vol_p0)
48545597088cSDongdong Hao return;
48555597088cSDongdong Hao
48565597088cSDongdong Hao vol_p1 = kzalloc_obj(*vol_p1);
48575597088cSDongdong Hao if (!vol_p1) {
48585597088cSDongdong Hao kfree(vol_p0);
48595597088cSDongdong Hao return;
48605597088cSDongdong Hao }
48615597088cSDongdong Hao
48625597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
48635597088cSDongdong Hao for (hdl = 0xFFFF, cfgp2.handle = hdl;
48645597088cSDongdong Hao !leapraid_op_config_page(adapter, vol_p1, cfgp1,
48655597088cSDongdong Hao cfgp2, GET_RAID_VOLUME_PG1);
48665597088cSDongdong Hao cfgp2.handle = hdl) {
48675597088cSDongdong Hao hdl = le16_to_cpu(vol_p1->dev_hdl);
48685597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_wwid(
48695597088cSDongdong Hao adapter,
48705597088cSDongdong Hao le64_to_cpu(vol_p1->wwid));
48715597088cSDongdong Hao if (raid_volume) {
48725597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
48735597088cSDongdong Hao continue;
48745597088cSDongdong Hao }
48755597088cSDongdong Hao
48765597088cSDongdong Hao cfgp1_extra.size = sizeof(struct leapraid_raidvol_p0);
48775597088cSDongdong Hao cfgp2_extra.handle = hdl;
48785597088cSDongdong Hao if (leapraid_op_config_page(adapter, vol_p0, cfgp1_extra,
48795597088cSDongdong Hao cfgp2_extra, GET_RAID_VOLUME_PG0))
48805597088cSDongdong Hao continue;
48815597088cSDongdong Hao
48825597088cSDongdong Hao if (vol_p0->volume_state == LEAPRAID_VOL_STATE_OPTIMAL ||
48835597088cSDongdong Hao vol_p0->volume_state == LEAPRAID_VOL_STATE_ONLINE ||
48845597088cSDongdong Hao vol_p0->volume_state == LEAPRAID_VOL_STATE_DEGRADED) {
48855597088cSDongdong Hao memset(&evt_data, 0,
48865597088cSDongdong Hao sizeof(struct leapraid_evt_data_ir_change));
48875597088cSDongdong Hao evt_data.reason_code = LEAPRAID_EVT_IR_RC_VOLUME_ADD;
48885597088cSDongdong Hao evt_data.vol_dev_hdl = vol_p1->dev_hdl;
48895597088cSDongdong Hao leapraid_sas_volume_add(adapter, &evt_data);
48905597088cSDongdong Hao dev_info(&adapter->pdev->dev,
48915597088cSDongdong Hao "add volume: hdl=0x%04x\n",
48925597088cSDongdong Hao vol_p1->dev_hdl);
48935597088cSDongdong Hao }
48945597088cSDongdong Hao }
48955597088cSDongdong Hao
48965597088cSDongdong Hao kfree(vol_p0);
48975597088cSDongdong Hao kfree(vol_p1);
48985597088cSDongdong Hao }
48995597088cSDongdong Hao
leapraid_scan_sas_dev_after_reset(struct leapraid_adapter * adapter)49005597088cSDongdong Hao static void leapraid_scan_sas_dev_after_reset(struct leapraid_adapter *adapter)
49015597088cSDongdong Hao {
49025597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
49035597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
49045597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
49055597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
49065597088cSDongdong Hao u16 hdl, parent_hdl;
49075597088cSDongdong Hao u64 sas_address;
49085597088cSDongdong Hao u8 port_id;
49095597088cSDongdong Hao
49105597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
49115597088cSDongdong Hao for (hdl = 0xFFFF, cfgp2.handle = hdl;
49125597088cSDongdong Hao !leapraid_op_config_page(adapter, &sas_dev_p0, cfgp1, cfgp2,
49135597088cSDongdong Hao GET_SAS_DEVICE_PG0);
49145597088cSDongdong Hao cfgp2.handle = hdl) {
49155597088cSDongdong Hao hdl = le16_to_cpu(sas_dev_p0.dev_hdl);
49165597088cSDongdong Hao if (!hdl ||
49175597088cSDongdong Hao hdl > adapter->adapter_attr.features.max_dev_handle) {
49185597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
49195597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
49205597088cSDongdong Hao continue;
49215597088cSDongdong Hao }
49225597088cSDongdong Hao
49235597088cSDongdong Hao if (!(leapraid_is_end_dev(le32_to_cpu(sas_dev_p0.dev_info))))
49245597088cSDongdong Hao continue;
49255597088cSDongdong Hao
49265597088cSDongdong Hao port_id = sas_dev_p0.physical_port;
49275597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_addr(
49285597088cSDongdong Hao adapter,
49295597088cSDongdong Hao le64_to_cpu(sas_dev_p0.sas_address),
49305597088cSDongdong Hao leapraid_get_port_by_id(
49315597088cSDongdong Hao adapter,
49325597088cSDongdong Hao port_id,
49335597088cSDongdong Hao false));
49345597088cSDongdong Hao if (sas_dev) {
49355597088cSDongdong Hao leapraid_sdev_put(sas_dev);
49365597088cSDongdong Hao continue;
49375597088cSDongdong Hao }
49385597088cSDongdong Hao
49395597088cSDongdong Hao parent_hdl = le16_to_cpu(sas_dev_p0.parent_dev_hdl);
49405597088cSDongdong Hao if (!leapraid_get_sas_address(adapter, parent_hdl,
49415597088cSDongdong Hao &sas_address)) {
49425597088cSDongdong Hao leapraid_transport_update_links(
49435597088cSDongdong Hao adapter,
49445597088cSDongdong Hao sas_address,
49455597088cSDongdong Hao hdl,
49465597088cSDongdong Hao sas_dev_p0.phy_num,
49475597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5,
49485597088cSDongdong Hao leapraid_get_port_by_id(adapter,
49495597088cSDongdong Hao port_id,
49505597088cSDongdong Hao false));
49515597088cSDongdong Hao leapraid_add_dev(adapter, hdl);
49525597088cSDongdong Hao dev_info(&adapter->pdev->dev,
49535597088cSDongdong Hao "Add SAS dev: hdl=0x%04x, saddr=0x%016llx\n",
49545597088cSDongdong Hao hdl,
49555597088cSDongdong Hao (unsigned long long)le64_to_cpu(
49565597088cSDongdong Hao sas_dev_p0.sas_address));
49575597088cSDongdong Hao }
49585597088cSDongdong Hao }
49595597088cSDongdong Hao }
49605597088cSDongdong Hao
leapraid_scan_all_dev_after_reset(struct leapraid_adapter * adapter)49615597088cSDongdong Hao static void leapraid_scan_all_dev_after_reset(struct leapraid_adapter *adapter)
49625597088cSDongdong Hao {
49635597088cSDongdong Hao leapraid_sas_host_add(adapter, adapter->dev_topo.card.phys_num > 0);
49645597088cSDongdong Hao leapraid_scan_exp_after_reset(adapter);
49655597088cSDongdong Hao if (adapter->adapter_attr.raid_support) {
49665597088cSDongdong Hao leapraid_scan_phy_disks_after_reset(adapter);
49675597088cSDongdong Hao leapraid_scan_vol_after_reset(adapter);
49685597088cSDongdong Hao }
49695597088cSDongdong Hao leapraid_scan_sas_dev_after_reset(adapter);
49705597088cSDongdong Hao }
49715597088cSDongdong Hao
leapraid_hardreset_async_logic(struct leapraid_adapter * adapter)49725597088cSDongdong Hao static void leapraid_hardreset_async_logic(struct leapraid_adapter *adapter)
49735597088cSDongdong Hao {
49745597088cSDongdong Hao unsigned long flags;
49755597088cSDongdong Hao
49765597088cSDongdong Hao leapraid_remove_unresp_dev(adapter);
49775597088cSDongdong Hao leapraid_del_dirty_vphy(adapter);
49785597088cSDongdong Hao leapraid_del_dirty_card_port(adapter);
49795597088cSDongdong Hao leapraid_update_dev_qdepth(adapter);
49805597088cSDongdong Hao leapraid_scan_all_dev_after_reset(adapter);
49815597088cSDongdong Hao
49825597088cSDongdong Hao if (adapter->scan_dev_desc.driver_loading)
49835597088cSDongdong Hao leapraid_scan_dev_done(adapter);
49845597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
49855597088cSDongdong Hao adapter->access_ctrl.shost_recover_async = 0;
49865597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
49875597088cSDongdong Hao wake_up(&adapter->access_ctrl.shost_recover_wq);
49885597088cSDongdong Hao }
49895597088cSDongdong Hao
leapraid_send_enc_cmd(struct leapraid_adapter * adapter,struct leapraid_sep_rep * sep_rep,struct leapraid_sep_req * sep_req)49905597088cSDongdong Hao static int leapraid_send_enc_cmd(struct leapraid_adapter *adapter,
49915597088cSDongdong Hao struct leapraid_sep_rep *sep_rep,
49925597088cSDongdong Hao struct leapraid_sep_req *sep_req)
49935597088cSDongdong Hao {
49945597088cSDongdong Hao void *req;
49955597088cSDongdong Hao bool reset_flg = false;
49965597088cSDongdong Hao int rc;
49975597088cSDongdong Hao u16 smid;
49985597088cSDongdong Hao
49995597088cSDongdong Hao mutex_lock(&adapter->driver_cmds.enc_cmd.mutex);
50005597088cSDongdong Hao rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
50015597088cSDongdong Hao __func__);
50025597088cSDongdong Hao if (rc)
50035597088cSDongdong Hao goto unlock;
50045597088cSDongdong Hao
50055597088cSDongdong Hao adapter->driver_cmds.enc_cmd.status = LEAPRAID_CMD_PENDING;
50065597088cSDongdong Hao smid = adapter->driver_cmds.enc_cmd.inter_taskid;
50075597088cSDongdong Hao req = leapraid_get_task_desc(adapter, smid);
50085597088cSDongdong Hao memset(req, 0, LEAPRAID_REQUEST_SIZE);
50095597088cSDongdong Hao memcpy(req, sep_req, sizeof(struct leapraid_sep_req));
50105597088cSDongdong Hao init_completion(&adapter->driver_cmds.enc_cmd.done);
50115597088cSDongdong Hao leapraid_fire_task(adapter, smid);
50125597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.enc_cmd.done,
50135597088cSDongdong Hao LEAPRAID_ENC_CMD_TIMEOUT * HZ);
50145597088cSDongdong Hao if (!(adapter->driver_cmds.enc_cmd.status & LEAPRAID_CMD_DONE)) {
50155597088cSDongdong Hao dev_err(&adapter->pdev->dev,
50165597088cSDongdong Hao "%s: SEP command timeout, status=0x%x\n",
50175597088cSDongdong Hao __func__, adapter->driver_cmds.enc_cmd.status);
50185597088cSDongdong Hao leapraid_log_req_context(adapter, smid, sep_req);
50195597088cSDongdong Hao reset_flg =
50205597088cSDongdong Hao leapraid_check_reset(
50215597088cSDongdong Hao adapter->driver_cmds.enc_cmd.status);
50225597088cSDongdong Hao rc = -EFAULT;
50235597088cSDongdong Hao goto do_hard_reset;
50245597088cSDongdong Hao }
50255597088cSDongdong Hao
50265597088cSDongdong Hao if (adapter->driver_cmds.enc_cmd.status & LEAPRAID_CMD_REPLY_VALID)
50275597088cSDongdong Hao memcpy(sep_rep, &adapter->driver_cmds.enc_cmd.reply,
50285597088cSDongdong Hao sizeof(struct leapraid_sep_rep));
50295597088cSDongdong Hao do_hard_reset:
50305597088cSDongdong Hao if (reset_flg) {
50315597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
50325597088cSDongdong Hao __func__, __LINE__);
50335597088cSDongdong Hao leapraid_hard_reset_handler(adapter, FULL_RESET);
50345597088cSDongdong Hao }
50355597088cSDongdong Hao
50365597088cSDongdong Hao adapter->driver_cmds.enc_cmd.status = LEAPRAID_CMD_NOT_USED;
50375597088cSDongdong Hao unlock:
50385597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.enc_cmd.mutex);
50395597088cSDongdong Hao return rc;
50405597088cSDongdong Hao }
50415597088cSDongdong Hao
leapraid_set_led(struct leapraid_adapter * adapter,struct leapraid_sas_dev * sas_dev,bool on)50425597088cSDongdong Hao static void leapraid_set_led(struct leapraid_adapter *adapter,
50435597088cSDongdong Hao struct leapraid_sas_dev *sas_dev, bool on)
50445597088cSDongdong Hao {
50455597088cSDongdong Hao struct leapraid_sep_rep sep_rep;
50465597088cSDongdong Hao struct leapraid_sep_req sep_req;
50475597088cSDongdong Hao
50485597088cSDongdong Hao if (!sas_dev)
50495597088cSDongdong Hao return;
50505597088cSDongdong Hao
50515597088cSDongdong Hao memset(&sep_req, 0, sizeof(struct leapraid_sep_req));
50525597088cSDongdong Hao memset(&sep_rep, 0, sizeof(struct leapraid_sep_rep));
50535597088cSDongdong Hao sep_req.func = LEAPRAID_FUNC_SCSI_ENC_PROCESSOR;
50545597088cSDongdong Hao sep_req.act = LEAPRAID_SEP_REQ_ACT_WRITE_STATUS;
50555597088cSDongdong Hao if (on) {
50565597088cSDongdong Hao u32 status = LEAPRAID_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
50575597088cSDongdong Hao
50585597088cSDongdong Hao sep_req.slot_status = cpu_to_le32(status);
50595597088cSDongdong Hao sep_req.dev_hdl = cpu_to_le16(sas_dev->hdl);
50605597088cSDongdong Hao sep_req.flg = LEAPRAID_SEP_REQ_FLG_DEVHDL_ADDRESS;
50615597088cSDongdong Hao if (leapraid_send_enc_cmd(adapter, &sep_rep, &sep_req)) {
50625597088cSDongdong Hao leapraid_sdev_put(sas_dev);
50635597088cSDongdong Hao return;
50645597088cSDongdong Hao }
50655597088cSDongdong Hao
50665597088cSDongdong Hao sas_dev->led_on = 1;
50675597088cSDongdong Hao leapraid_sdev_put(sas_dev);
50685597088cSDongdong Hao } else {
50695597088cSDongdong Hao sep_req.slot_status = 0;
50705597088cSDongdong Hao sep_req.slot = cpu_to_le16(sas_dev->slot);
50715597088cSDongdong Hao sep_req.dev_hdl = 0;
50725597088cSDongdong Hao sep_req.enc_hdl = cpu_to_le16(sas_dev->enc_hdl);
50735597088cSDongdong Hao sep_req.flg = LEAPRAID_SEP_REQ_FLG_ENCLOSURE_SLOT_ADDRESS;
50745597088cSDongdong Hao leapraid_send_enc_cmd(adapter, &sep_rep, &sep_req);
50755597088cSDongdong Hao }
50765597088cSDongdong Hao }
50775597088cSDongdong Hao
leapraid_wait_adapter_recovery(struct leapraid_adapter * adapter)50785597088cSDongdong Hao static int leapraid_wait_adapter_recovery(struct leapraid_adapter *adapter)
50795597088cSDongdong Hao {
50805597088cSDongdong Hao unsigned long flags;
50815597088cSDongdong Hao
50825597088cSDongdong Hao while (leapraid_shost_in_recovery(adapter->shost) ||
50835597088cSDongdong Hao READ_ONCE(adapter->access_ctrl.shost_recovering)) {
50845597088cSDongdong Hao if (READ_ONCE(adapter->access_ctrl.host_removing) ||
50855597088cSDongdong Hao READ_ONCE(adapter->fw_evt_s.fw_evt_cleanup)) {
50865597088cSDongdong Hao spin_lock_irqsave(
50875597088cSDongdong Hao &adapter->reset_desc.adapter_reset_lock,
50885597088cSDongdong Hao flags);
50895597088cSDongdong Hao adapter->access_ctrl.shost_recover_async = 0;
50905597088cSDongdong Hao spin_unlock_irqrestore(
50915597088cSDongdong Hao &adapter->reset_desc.adapter_reset_lock,
50925597088cSDongdong Hao flags);
50935597088cSDongdong Hao
50945597088cSDongdong Hao wake_up(&adapter->access_ctrl.shost_recover_wq);
50955597088cSDongdong Hao
50965597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
50975597088cSDongdong Hao "%s: Failed, shost %d, host %d\n",
50985597088cSDongdong Hao __func__,
50995597088cSDongdong Hao adapter->access_ctrl.shost_recovering,
51005597088cSDongdong Hao adapter->access_ctrl.host_removing);
51015597088cSDongdong Hao
51025597088cSDongdong Hao return -EFAULT;
51035597088cSDongdong Hao }
51045597088cSDongdong Hao
51055597088cSDongdong Hao wait_event_timeout(
51065597088cSDongdong Hao adapter->access_ctrl.recovery_waitq,
51075597088cSDongdong Hao (!leapraid_shost_in_recovery(adapter->shost) &&
51085597088cSDongdong Hao !READ_ONCE(adapter->access_ctrl.shost_recovering)),
51095597088cSDongdong Hao msecs_to_jiffies(1000));
51105597088cSDongdong Hao }
51115597088cSDongdong Hao
51125597088cSDongdong Hao return 0;
51135597088cSDongdong Hao }
51145597088cSDongdong Hao
leapraid_fw_work(struct leapraid_adapter * adapter,struct leapraid_fw_evt_work * fw_evt)51155597088cSDongdong Hao static void leapraid_fw_work(struct leapraid_adapter *adapter,
51165597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt)
51175597088cSDongdong Hao {
51185597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
51195597088cSDongdong Hao unsigned long flags;
51205597088cSDongdong Hao
51215597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
51225597088cSDongdong Hao adapter->fw_evt_s.cur_evt = fw_evt;
51235597088cSDongdong Hao adapter->fw_evt_s.cur_evt_task = current;
51245597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
51255597088cSDongdong Hao leapraid_del_fw_evt_from_list(adapter, fw_evt);
51265597088cSDongdong Hao if (adapter->access_ctrl.host_removing ||
51275597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) {
51285597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
51295597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
51305597088cSDongdong Hao adapter->fw_evt_s.cur_evt = NULL;
51315597088cSDongdong Hao adapter->fw_evt_s.cur_evt_task = NULL;
51325597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
51335597088cSDongdong Hao return;
51345597088cSDongdong Hao }
51355597088cSDongdong Hao switch (fw_evt->evt_type) {
51365597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_CHANGE_LIST:
51375597088cSDongdong Hao leapraid_sas_topo_chg_evt(adapter, fw_evt);
51385597088cSDongdong Hao break;
51395597088cSDongdong Hao case LEAPRAID_EVT_IR_CHANGE:
51405597088cSDongdong Hao leapraid_sas_ir_chg_evt(adapter, fw_evt);
51415597088cSDongdong Hao break;
51425597088cSDongdong Hao case LEAPRAID_EVT_SAS_ENCL_DEV_STATUS_CHANGE:
51435597088cSDongdong Hao leapraid_sas_enc_dev_stat_chg_evt(adapter, fw_evt);
51445597088cSDongdong Hao break;
51455597088cSDongdong Hao case LEAPRAID_EVT_REMOVE_DEAD_DEV:
51465597088cSDongdong Hao if (leapraid_wait_adapter_recovery(adapter))
51475597088cSDongdong Hao goto out_cleanup;
51485597088cSDongdong Hao
51495597088cSDongdong Hao leapraid_hardreset_async_logic(adapter);
51505597088cSDongdong Hao break;
51515597088cSDongdong Hao case LEAPRAID_EVT_TURN_ON_PFA_LED:
51525597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_hdl(adapter,
51535597088cSDongdong Hao fw_evt->dev_handle);
51545597088cSDongdong Hao leapraid_set_led(adapter, sas_dev, true);
51555597088cSDongdong Hao break;
51565597088cSDongdong Hao case LEAPRAID_EVT_SCAN_DEV_DONE:
51575597088cSDongdong Hao adapter->scan_dev_desc.scan_start = 0;
51585597088cSDongdong Hao break;
51595597088cSDongdong Hao default:
51605597088cSDongdong Hao break;
51615597088cSDongdong Hao }
51625597088cSDongdong Hao out_cleanup:
51635597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
51645597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
51655597088cSDongdong Hao adapter->fw_evt_s.cur_evt = NULL;
51665597088cSDongdong Hao adapter->fw_evt_s.cur_evt_task = NULL;
51675597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
51685597088cSDongdong Hao }
51695597088cSDongdong Hao
leapraid_sas_dev_stat_chg_evt(struct leapraid_adapter * adapter,struct leapraid_evt_data_sas_dev_status_change * event_data)51705597088cSDongdong Hao static void leapraid_sas_dev_stat_chg_evt(
51715597088cSDongdong Hao struct leapraid_adapter *adapter,
51725597088cSDongdong Hao struct leapraid_evt_data_sas_dev_status_change *event_data)
51735597088cSDongdong Hao {
51745597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
51755597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
51765597088cSDongdong Hao u64 sas_address;
51775597088cSDongdong Hao unsigned long flags;
51785597088cSDongdong Hao
51795597088cSDongdong Hao switch (event_data->reason_code) {
51805597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STAT_RC_INTERNAL_DEV_RESET:
51815597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
51825597088cSDongdong Hao break;
51835597088cSDongdong Hao default:
51845597088cSDongdong Hao return;
51855597088cSDongdong Hao }
51865597088cSDongdong Hao
51875597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
51885597088cSDongdong Hao
51895597088cSDongdong Hao sas_address = le64_to_cpu(event_data->sas_address);
51905597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr(
51915597088cSDongdong Hao adapter,
51925597088cSDongdong Hao sas_address,
51935597088cSDongdong Hao leapraid_get_port_by_id(adapter,
51945597088cSDongdong Hao event_data->physical_port,
51955597088cSDongdong Hao false));
51965597088cSDongdong Hao if (!sas_dev || !sas_dev->starget)
51975597088cSDongdong Hao goto out_unlock;
51985597088cSDongdong Hao
51995597088cSDongdong Hao starget_priv = sas_dev->starget->hostdata;
52005597088cSDongdong Hao if (starget_priv) {
52015597088cSDongdong Hao switch (event_data->reason_code) {
52025597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STAT_RC_INTERNAL_DEV_RESET:
52035597088cSDongdong Hao starget_priv->tm_busy = 1;
52045597088cSDongdong Hao break;
52055597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
52065597088cSDongdong Hao starget_priv->tm_busy = 0;
52075597088cSDongdong Hao break;
52085597088cSDongdong Hao }
52095597088cSDongdong Hao }
52105597088cSDongdong Hao
52115597088cSDongdong Hao out_unlock:
52125597088cSDongdong Hao if (sas_dev)
52135597088cSDongdong Hao leapraid_sdev_put(sas_dev);
52145597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
52155597088cSDongdong Hao }
52165597088cSDongdong Hao
leapraid_set_volume_delete_flag(struct leapraid_adapter * adapter,u16 handle)52175597088cSDongdong Hao static void leapraid_set_volume_delete_flag(struct leapraid_adapter *adapter,
52185597088cSDongdong Hao u16 handle)
52195597088cSDongdong Hao {
52205597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
52215597088cSDongdong Hao struct leapraid_starget_priv *sas_target_priv_data;
52225597088cSDongdong Hao unsigned long flags;
52235597088cSDongdong Hao
52245597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_hdl(adapter, handle);
52255597088cSDongdong Hao if (raid_volume) {
52265597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
52275597088cSDongdong Hao if (raid_volume->starget &&
52285597088cSDongdong Hao raid_volume->starget->hostdata) {
52295597088cSDongdong Hao sas_target_priv_data = raid_volume->starget->hostdata;
52305597088cSDongdong Hao sas_target_priv_data->deleted = 1;
52315597088cSDongdong Hao }
52325597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
52335597088cSDongdong Hao flags);
52345597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
52355597088cSDongdong Hao }
52365597088cSDongdong Hao }
52375597088cSDongdong Hao
leapraid_check_ir_change_evt(struct leapraid_adapter * adapter,struct leapraid_evt_data_ir_change * evt_data)52385597088cSDongdong Hao static void leapraid_check_ir_change_evt(
52395597088cSDongdong Hao struct leapraid_adapter *adapter,
52405597088cSDongdong Hao struct leapraid_evt_data_ir_change *evt_data)
52415597088cSDongdong Hao {
52425597088cSDongdong Hao u16 phys_disk_dev_hdl;
52435597088cSDongdong Hao
52445597088cSDongdong Hao switch (evt_data->reason_code) {
52455597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_VOLUME_DELETE:
52465597088cSDongdong Hao leapraid_set_volume_delete_flag(
52475597088cSDongdong Hao adapter,
52485597088cSDongdong Hao le16_to_cpu(evt_data->vol_dev_hdl));
52495597088cSDongdong Hao break;
52505597088cSDongdong Hao case LEAPRAID_EVT_IR_RC_PD_UNHIDDEN_TO_DELETE:
52515597088cSDongdong Hao phys_disk_dev_hdl =
52525597088cSDongdong Hao le16_to_cpu(evt_data->phys_disk_dev_hdl);
52535597088cSDongdong Hao if (!phys_disk_dev_hdl ||
52545597088cSDongdong Hao phys_disk_dev_hdl >
52555597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle) {
52565597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
52575597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
52585597088cSDongdong Hao } else {
52595597088cSDongdong Hao clear_bit(phys_disk_dev_hdl,
52605597088cSDongdong Hao adapter->dev_topo.pd_hdls);
52615597088cSDongdong Hao leapraid_tgt_rst_send(adapter, phys_disk_dev_hdl);
52625597088cSDongdong Hao }
52635597088cSDongdong Hao break;
52645597088cSDongdong Hao }
52655597088cSDongdong Hao }
52665597088cSDongdong Hao
leapraid_topo_del_evts_process_exp_status(struct leapraid_adapter * adapter,struct leapraid_evt_data_sas_topo_change_list * evt_data)52675597088cSDongdong Hao static void leapraid_topo_del_evts_process_exp_status(
52685597088cSDongdong Hao struct leapraid_adapter *adapter,
52695597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *evt_data)
52705597088cSDongdong Hao {
52715597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt = NULL;
52725597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *loc_evt_data;
52735597088cSDongdong Hao unsigned long flags;
52745597088cSDongdong Hao u16 exp_hdl;
52755597088cSDongdong Hao
52765597088cSDongdong Hao exp_hdl = le16_to_cpu(evt_data->exp_dev_hdl);
52775597088cSDongdong Hao
52785597088cSDongdong Hao switch (evt_data->exp_status) {
52795597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_ES_NOT_RESPONDING:
52805597088cSDongdong Hao spin_lock_irqsave(&adapter->fw_evt_s.fw_evt_lock, flags);
52815597088cSDongdong Hao list_for_each_entry(fw_evt,
52825597088cSDongdong Hao &adapter->fw_evt_s.fw_evt_list, list) {
52835597088cSDongdong Hao if (fw_evt->evt_type !=
52845597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_CHANGE_LIST ||
52855597088cSDongdong Hao fw_evt->ignore)
52865597088cSDongdong Hao continue;
52875597088cSDongdong Hao
52885597088cSDongdong Hao loc_evt_data = fw_evt->evt_data;
52895597088cSDongdong Hao if ((loc_evt_data->exp_status ==
52905597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_ES_ADDED ||
52915597088cSDongdong Hao loc_evt_data->exp_status ==
52925597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_ES_RESPONDING) &&
52935597088cSDongdong Hao le16_to_cpu(loc_evt_data->exp_dev_hdl) == exp_hdl)
52945597088cSDongdong Hao fw_evt->ignore = 1;
52955597088cSDongdong Hao }
52965597088cSDongdong Hao spin_unlock_irqrestore(&adapter->fw_evt_s.fw_evt_lock, flags);
52975597088cSDongdong Hao break;
52985597088cSDongdong Hao default:
52995597088cSDongdong Hao break;
53005597088cSDongdong Hao }
53015597088cSDongdong Hao }
53025597088cSDongdong Hao
leapraid_check_topo_del_evts(struct leapraid_adapter * adapter,struct leapraid_evt_data_sas_topo_change_list * evt_data)53035597088cSDongdong Hao static void leapraid_check_topo_del_evts(
53045597088cSDongdong Hao struct leapraid_adapter *adapter,
53055597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *evt_data)
53065597088cSDongdong Hao {
53075597088cSDongdong Hao int reason_code;
53085597088cSDongdong Hao u16 hdl;
53095597088cSDongdong Hao int i;
53105597088cSDongdong Hao
53115597088cSDongdong Hao for (i = 0; i < evt_data->entry_num; i++) {
53125597088cSDongdong Hao hdl = le16_to_cpu(evt_data->phy[i].attached_dev_hdl);
53135597088cSDongdong Hao if (!hdl)
53145597088cSDongdong Hao continue;
53155597088cSDongdong Hao
53165597088cSDongdong Hao reason_code = evt_data->phy[i].phy_status &
53175597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_RC_MASK;
53185597088cSDongdong Hao if (reason_code ==
53195597088cSDongdong Hao LEAPRAID_EVT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
53205597088cSDongdong Hao leapraid_tgt_not_responding(adapter, hdl);
53215597088cSDongdong Hao }
53225597088cSDongdong Hao leapraid_topo_del_evts_process_exp_status(adapter, evt_data);
53235597088cSDongdong Hao }
53245597088cSDongdong Hao
leapraid_async_evt_validate(struct leapraid_adapter * adapter,struct leapraid_evt_notify_rep * event_notify_rep)53255597088cSDongdong Hao static bool leapraid_async_evt_validate(
53265597088cSDongdong Hao struct leapraid_adapter *adapter,
53275597088cSDongdong Hao struct leapraid_evt_notify_rep *event_notify_rep)
53285597088cSDongdong Hao {
53295597088cSDongdong Hao size_t msg_len;
53305597088cSDongdong Hao size_t evt_sz;
53315597088cSDongdong Hao size_t evt_avail;
53325597088cSDongdong Hao u16 evt;
53335597088cSDongdong Hao
53345597088cSDongdong Hao msg_len = event_notify_rep->msg_len * sizeof(u32);
53355597088cSDongdong Hao if (msg_len > LEAPRAID_REPLY_SIZE ||
53365597088cSDongdong Hao msg_len < offsetof(struct leapraid_evt_notify_rep, evt_data)) {
53375597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
53385597088cSDongdong Hao "%s: Invalid async event msg_len=%zu\n",
53395597088cSDongdong Hao __func__, msg_len);
53405597088cSDongdong Hao return false;
53415597088cSDongdong Hao }
53425597088cSDongdong Hao
53435597088cSDongdong Hao evt_sz = le16_to_cpu(event_notify_rep->evt_data_len) * sizeof(u32);
53445597088cSDongdong Hao evt_avail = msg_len -
53455597088cSDongdong Hao offsetof(struct leapraid_evt_notify_rep, evt_data);
53465597088cSDongdong Hao if (evt_sz > evt_avail) {
53475597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
53485597088cSDongdong Hao "%s: Invalid async event evt_data_len=%zu\n",
53495597088cSDongdong Hao __func__, evt_sz);
53505597088cSDongdong Hao return false;
53515597088cSDongdong Hao }
53525597088cSDongdong Hao
53535597088cSDongdong Hao evt = le16_to_cpu(event_notify_rep->evt);
53545597088cSDongdong Hao switch (evt) {
53555597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STATUS_CHANGE:
53565597088cSDongdong Hao if (evt_sz <
53575597088cSDongdong Hao sizeof(struct leapraid_evt_data_sas_dev_status_change))
53585597088cSDongdong Hao goto invalid_evt_sz;
53595597088cSDongdong Hao break;
53605597088cSDongdong Hao case LEAPRAID_EVT_IR_CHANGE:
53615597088cSDongdong Hao if (evt_sz < sizeof(struct leapraid_evt_data_ir_change))
53625597088cSDongdong Hao goto invalid_evt_sz;
53635597088cSDongdong Hao break;
53645597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_CHANGE_LIST:
53655597088cSDongdong Hao {
53665597088cSDongdong Hao struct leapraid_evt_data_sas_topo_change_list *evt_data =
53675597088cSDongdong Hao (void *)event_notify_rep->evt_data;
53685597088cSDongdong Hao size_t hdr_sz;
53695597088cSDongdong Hao
53705597088cSDongdong Hao hdr_sz =
53715597088cSDongdong Hao offsetof(struct leapraid_evt_data_sas_topo_change_list,
53725597088cSDongdong Hao phy);
53735597088cSDongdong Hao if (evt_sz < hdr_sz)
53745597088cSDongdong Hao goto invalid_evt_sz;
53755597088cSDongdong Hao
53765597088cSDongdong Hao if (evt_data->entry_num >
53775597088cSDongdong Hao (evt_sz - hdr_sz) / sizeof(evt_data->phy[0]))
53785597088cSDongdong Hao goto invalid_evt_sz;
53795597088cSDongdong Hao break;
53805597088cSDongdong Hao }
53815597088cSDongdong Hao case LEAPRAID_EVT_SAS_ENCL_DEV_STATUS_CHANGE:
53825597088cSDongdong Hao if (evt_sz <
53835597088cSDongdong Hao sizeof(struct leapraid_evt_data_sas_enc_dev_status_change))
53845597088cSDongdong Hao goto invalid_evt_sz;
53855597088cSDongdong Hao break;
53865597088cSDongdong Hao default:
53875597088cSDongdong Hao break;
53885597088cSDongdong Hao }
53895597088cSDongdong Hao
53905597088cSDongdong Hao return true;
53915597088cSDongdong Hao
53925597088cSDongdong Hao invalid_evt_sz:
53935597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
53945597088cSDongdong Hao "%s: Invalid async event size=%zu for evt=0x%x\n",
53955597088cSDongdong Hao __func__, evt_sz, evt);
53965597088cSDongdong Hao return false;
53975597088cSDongdong Hao }
53985597088cSDongdong Hao
leapraid_async_process_evt(struct leapraid_adapter * adapter,struct leapraid_evt_notify_rep * event_notify_rep)53995597088cSDongdong Hao static bool leapraid_async_process_evt(
54005597088cSDongdong Hao struct leapraid_adapter *adapter,
54015597088cSDongdong Hao struct leapraid_evt_notify_rep *event_notify_rep)
54025597088cSDongdong Hao {
54035597088cSDongdong Hao u16 evt = le16_to_cpu(event_notify_rep->evt);
54045597088cSDongdong Hao bool exit_flag = false;
54055597088cSDongdong Hao
54065597088cSDongdong Hao if (adapter->access_ctrl.host_removing ||
54075597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
54085597088cSDongdong Hao return true;
54095597088cSDongdong Hao
54105597088cSDongdong Hao switch (evt) {
54115597088cSDongdong Hao case LEAPRAID_EVT_SAS_DEV_STATUS_CHANGE:
54125597088cSDongdong Hao leapraid_sas_dev_stat_chg_evt(
54135597088cSDongdong Hao adapter,
54145597088cSDongdong Hao (struct leapraid_evt_data_sas_dev_status_change
54155597088cSDongdong Hao *)event_notify_rep->evt_data);
54165597088cSDongdong Hao break;
54175597088cSDongdong Hao case LEAPRAID_EVT_IR_CHANGE:
54185597088cSDongdong Hao leapraid_check_ir_change_evt(
54195597088cSDongdong Hao adapter,
54205597088cSDongdong Hao (struct leapraid_evt_data_ir_change
54215597088cSDongdong Hao *)event_notify_rep->evt_data);
54225597088cSDongdong Hao break;
54235597088cSDongdong Hao case LEAPRAID_EVT_SAS_TOPO_CHANGE_LIST:
54245597088cSDongdong Hao leapraid_check_topo_del_evts(
54255597088cSDongdong Hao adapter,
54265597088cSDongdong Hao (struct leapraid_evt_data_sas_topo_change_list
54275597088cSDongdong Hao *)event_notify_rep->evt_data);
54285597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering) {
54295597088cSDongdong Hao exit_flag = true;
54305597088cSDongdong Hao return exit_flag;
54315597088cSDongdong Hao }
54325597088cSDongdong Hao break;
54335597088cSDongdong Hao case LEAPRAID_EVT_SAS_ENCL_DEV_STATUS_CHANGE:
54345597088cSDongdong Hao break;
54355597088cSDongdong Hao default:
54365597088cSDongdong Hao exit_flag = true;
54375597088cSDongdong Hao return exit_flag;
54385597088cSDongdong Hao }
54395597088cSDongdong Hao
54405597088cSDongdong Hao return exit_flag;
54415597088cSDongdong Hao }
54425597088cSDongdong Hao
leapraid_async_evt_cb_enqueue(struct leapraid_adapter * adapter,struct leapraid_evt_notify_rep * evt_notify_rep)54435597088cSDongdong Hao static void leapraid_async_evt_cb_enqueue(
54445597088cSDongdong Hao struct leapraid_adapter *adapter,
54455597088cSDongdong Hao struct leapraid_evt_notify_rep *evt_notify_rep)
54465597088cSDongdong Hao {
54475597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt;
54485597088cSDongdong Hao u16 evt_sz;
54495597088cSDongdong Hao
54505597088cSDongdong Hao fw_evt = leapraid_alloc_fw_evt_work();
54515597088cSDongdong Hao if (!fw_evt)
54525597088cSDongdong Hao return;
54535597088cSDongdong Hao
54545597088cSDongdong Hao evt_sz = le16_to_cpu(evt_notify_rep->evt_data_len) * sizeof(u32);
54555597088cSDongdong Hao fw_evt->evt_data = kmemdup(evt_notify_rep->evt_data,
54565597088cSDongdong Hao evt_sz, GFP_ATOMIC);
54575597088cSDongdong Hao if (!fw_evt->evt_data) {
54585597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
54595597088cSDongdong Hao return;
54605597088cSDongdong Hao }
54615597088cSDongdong Hao fw_evt->adapter = adapter;
54625597088cSDongdong Hao fw_evt->evt_type = le16_to_cpu(evt_notify_rep->evt);
54635597088cSDongdong Hao leapraid_fw_evt_add(adapter, fw_evt);
54645597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
54655597088cSDongdong Hao }
54665597088cSDongdong Hao
leapraid_async_evt_cb(struct leapraid_adapter * adapter,u8 msix_index,u32 rep_paddr)54675597088cSDongdong Hao static void leapraid_async_evt_cb(struct leapraid_adapter *adapter,
54685597088cSDongdong Hao u8 msix_index, u32 rep_paddr)
54695597088cSDongdong Hao {
54705597088cSDongdong Hao struct leapraid_evt_notify_rep *evt_notify_rep;
54715597088cSDongdong Hao
54725597088cSDongdong Hao if (adapter->access_ctrl.host_removing ||
54735597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
54745597088cSDongdong Hao return;
54755597088cSDongdong Hao
54765597088cSDongdong Hao evt_notify_rep = leapraid_get_reply_vaddr(adapter, rep_paddr);
54775597088cSDongdong Hao if (unlikely(!evt_notify_rep))
54785597088cSDongdong Hao return;
54795597088cSDongdong Hao
54805597088cSDongdong Hao if (!leapraid_async_evt_validate(adapter, evt_notify_rep))
54815597088cSDongdong Hao return;
54825597088cSDongdong Hao
54835597088cSDongdong Hao if (leapraid_async_process_evt(adapter, evt_notify_rep))
54845597088cSDongdong Hao return;
54855597088cSDongdong Hao
54865597088cSDongdong Hao leapraid_async_evt_cb_enqueue(adapter, evt_notify_rep);
54875597088cSDongdong Hao }
54885597088cSDongdong Hao
leapraid_handle_async_event(struct leapraid_adapter * adapter,u8 msix_index,u32 reply)54895597088cSDongdong Hao static void leapraid_handle_async_event(struct leapraid_adapter *adapter,
54905597088cSDongdong Hao u8 msix_index, u32 reply)
54915597088cSDongdong Hao {
54925597088cSDongdong Hao struct leapraid_evt_notify_rep *leap_mpi_rep =
54935597088cSDongdong Hao leapraid_get_reply_vaddr(adapter, reply);
54945597088cSDongdong Hao
54955597088cSDongdong Hao if (!leap_mpi_rep)
54965597088cSDongdong Hao return;
54975597088cSDongdong Hao
54985597088cSDongdong Hao if (leap_mpi_rep->func != LEAPRAID_FUNC_EVENT_NOTIFY)
54995597088cSDongdong Hao return;
55005597088cSDongdong Hao
55015597088cSDongdong Hao leapraid_async_evt_cb(adapter, msix_index, reply);
55025597088cSDongdong Hao }
55035597088cSDongdong Hao
leapraid_async_turn_on_led(struct leapraid_adapter * adapter,u16 handle)55045597088cSDongdong Hao void leapraid_async_turn_on_led(struct leapraid_adapter *adapter, u16 handle)
55055597088cSDongdong Hao {
55065597088cSDongdong Hao struct leapraid_fw_evt_work *fw_event;
55075597088cSDongdong Hao
55085597088cSDongdong Hao fw_event = leapraid_alloc_fw_evt_work();
55095597088cSDongdong Hao if (!fw_event)
55105597088cSDongdong Hao return;
55115597088cSDongdong Hao
55125597088cSDongdong Hao fw_event->dev_handle = handle;
55135597088cSDongdong Hao fw_event->adapter = adapter;
55145597088cSDongdong Hao fw_event->evt_type = LEAPRAID_EVT_TURN_ON_PFA_LED;
55155597088cSDongdong Hao leapraid_fw_evt_add(adapter, fw_event);
55165597088cSDongdong Hao leapraid_fw_evt_put(fw_event);
55175597088cSDongdong Hao }
55185597088cSDongdong Hao
leapraid_hardreset_barrier(struct leapraid_adapter * adapter)55195597088cSDongdong Hao static void leapraid_hardreset_barrier(struct leapraid_adapter *adapter)
55205597088cSDongdong Hao {
55215597088cSDongdong Hao struct leapraid_fw_evt_work *fw_event;
55225597088cSDongdong Hao
55235597088cSDongdong Hao fw_event = leapraid_alloc_fw_evt_work();
55245597088cSDongdong Hao if (!fw_event)
55255597088cSDongdong Hao return;
55265597088cSDongdong Hao
55275597088cSDongdong Hao fw_event->adapter = adapter;
55285597088cSDongdong Hao fw_event->evt_type = LEAPRAID_EVT_REMOVE_DEAD_DEV;
55295597088cSDongdong Hao leapraid_fw_evt_add(adapter, fw_event);
55305597088cSDongdong Hao leapraid_fw_evt_put(fw_event);
55315597088cSDongdong Hao }
55325597088cSDongdong Hao
leapraid_scan_dev_complete(struct leapraid_adapter * adapter)55335597088cSDongdong Hao static void leapraid_scan_dev_complete(struct leapraid_adapter *adapter)
55345597088cSDongdong Hao {
55355597088cSDongdong Hao struct leapraid_fw_evt_work *fw_evt;
55365597088cSDongdong Hao
55375597088cSDongdong Hao fw_evt = leapraid_alloc_fw_evt_work();
55385597088cSDongdong Hao if (!fw_evt)
55395597088cSDongdong Hao return;
55405597088cSDongdong Hao
55415597088cSDongdong Hao fw_evt->evt_type = LEAPRAID_EVT_SCAN_DEV_DONE;
55425597088cSDongdong Hao fw_evt->adapter = adapter;
55435597088cSDongdong Hao leapraid_fw_evt_add(adapter, fw_evt);
55445597088cSDongdong Hao leapraid_fw_evt_put(fw_evt);
55455597088cSDongdong Hao }
55465597088cSDongdong Hao
leapraid_handle_scan_cb(struct leapraid_adapter * adapter,struct leapraid_driver_cmd * cmd,struct leapraid_rep * rep)55475597088cSDongdong Hao static void leapraid_handle_scan_cb(struct leapraid_adapter *adapter,
55485597088cSDongdong Hao struct leapraid_driver_cmd *cmd,
55495597088cSDongdong Hao struct leapraid_rep *rep)
55505597088cSDongdong Hao {
55515597088cSDongdong Hao u16 status;
55525597088cSDongdong Hao
55535597088cSDongdong Hao cmd->status &= ~LEAPRAID_CMD_PENDING;
55545597088cSDongdong Hao
55555597088cSDongdong Hao status = le16_to_cpu(rep->adapter_status) &
55565597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
55575597088cSDongdong Hao if (status != LEAPRAID_ADAPTER_STATUS_SUCCESS)
55585597088cSDongdong Hao adapter->scan_dev_desc.scan_dev_failed = 1;
55595597088cSDongdong Hao
55605597088cSDongdong Hao if (!cmd->async_scan_dev) {
55615597088cSDongdong Hao complete(&cmd->done);
55625597088cSDongdong Hao return;
55635597088cSDongdong Hao }
55645597088cSDongdong Hao
55655597088cSDongdong Hao if (status == LEAPRAID_ADAPTER_STATUS_SUCCESS)
55665597088cSDongdong Hao leapraid_scan_dev_complete(adapter);
55675597088cSDongdong Hao else
55685597088cSDongdong Hao adapter->scan_dev_desc.scan_start_failed = status;
55695597088cSDongdong Hao }
55705597088cSDongdong Hao
leapraid_handle_ctl_cb(struct leapraid_adapter * adapter,struct leapraid_rep * rep,u16 taskid)55715597088cSDongdong Hao static void leapraid_handle_ctl_cb(struct leapraid_adapter *adapter,
55725597088cSDongdong Hao struct leapraid_rep *rep,
55735597088cSDongdong Hao u16 taskid)
55745597088cSDongdong Hao {
55755597088cSDongdong Hao struct leapraid_scsiio_rep *scsiio_reply;
55765597088cSDongdong Hao
55775597088cSDongdong Hao if (rep->function != LEAPRAID_FUNC_SCSIIO &&
55785597088cSDongdong Hao rep->function != LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH)
55795597088cSDongdong Hao return;
55805597088cSDongdong Hao
55815597088cSDongdong Hao scsiio_reply = (struct leapraid_scsiio_rep *)rep;
55825597088cSDongdong Hao if (!(scsiio_reply->scsi_state &
55835597088cSDongdong Hao LEAPRAID_SCSI_STATE_AUTOSENSE_VALID))
55845597088cSDongdong Hao return;
55855597088cSDongdong Hao
55865597088cSDongdong Hao memcpy(&adapter->driver_cmds.ctl_cmd.sense,
55875597088cSDongdong Hao leapraid_get_sense_buffer(adapter, taskid),
55885597088cSDongdong Hao min_t(u32, SCSI_SENSE_BUFFERSIZE,
55895597088cSDongdong Hao le32_to_cpu(scsiio_reply->sense_count)));
55905597088cSDongdong Hao }
55915597088cSDongdong Hao
leapraid_driver_cmds_done(struct leapraid_adapter * adapter,u16 taskid,u8 msix_index,u32 rep_paddr,u8 cb_idx)55925597088cSDongdong Hao static bool leapraid_driver_cmds_done(struct leapraid_adapter *adapter,
55935597088cSDongdong Hao u16 taskid, u8 msix_index,
55945597088cSDongdong Hao u32 rep_paddr, u8 cb_idx)
55955597088cSDongdong Hao {
55965597088cSDongdong Hao struct leapraid_rep *leap_mpi_rep =
55975597088cSDongdong Hao leapraid_get_reply_vaddr(adapter, rep_paddr);
55985597088cSDongdong Hao struct leapraid_driver_cmd *sp_cmd, *_sp_cmd = NULL;
55995597088cSDongdong Hao u8 reply_len;
56005597088cSDongdong Hao
56015597088cSDongdong Hao list_for_each_entry(sp_cmd, &adapter->driver_cmds.special_cmd_list,
56025597088cSDongdong Hao list)
56035597088cSDongdong Hao if (cb_idx == sp_cmd->cb_idx) {
56045597088cSDongdong Hao _sp_cmd = sp_cmd;
56055597088cSDongdong Hao break;
56065597088cSDongdong Hao }
56075597088cSDongdong Hao
56085597088cSDongdong Hao if (WARN_ON(!_sp_cmd))
56095597088cSDongdong Hao return true;
56105597088cSDongdong Hao if (WARN_ON(_sp_cmd->status == LEAPRAID_CMD_NOT_USED))
56115597088cSDongdong Hao return true;
56125597088cSDongdong Hao if (WARN_ON(taskid != _sp_cmd->hp_taskid &&
56135597088cSDongdong Hao taskid != _sp_cmd->taskid &&
56145597088cSDongdong Hao taskid != _sp_cmd->inter_taskid))
56155597088cSDongdong Hao return true;
56165597088cSDongdong Hao _sp_cmd->status |= LEAPRAID_CMD_DONE;
56175597088cSDongdong Hao if (leap_mpi_rep) {
56185597088cSDongdong Hao reply_len = leap_mpi_rep->msg_len * sizeof(u32);
56195597088cSDongdong Hao if (reply_len > LEAPRAID_REPLY_SIZE)
56205597088cSDongdong Hao reply_len = LEAPRAID_REPLY_SIZE;
56215597088cSDongdong Hao memcpy(&_sp_cmd->reply, leap_mpi_rep, reply_len);
56225597088cSDongdong Hao _sp_cmd->status |= LEAPRAID_CMD_REPLY_VALID;
56235597088cSDongdong Hao
56245597088cSDongdong Hao if (_sp_cmd->cb_idx == LEAPRAID_SCAN_DEV_CB_IDX) {
56255597088cSDongdong Hao leapraid_handle_scan_cb(adapter, _sp_cmd,
56265597088cSDongdong Hao leap_mpi_rep);
56275597088cSDongdong Hao return true;
56285597088cSDongdong Hao }
56295597088cSDongdong Hao
56305597088cSDongdong Hao if (_sp_cmd->cb_idx == LEAPRAID_CTL_CB_IDX)
56315597088cSDongdong Hao leapraid_handle_ctl_cb(adapter, leap_mpi_rep, taskid);
56325597088cSDongdong Hao }
56335597088cSDongdong Hao
56345597088cSDongdong Hao _sp_cmd->status &= ~LEAPRAID_CMD_PENDING;
56355597088cSDongdong Hao complete(&_sp_cmd->done);
56365597088cSDongdong Hao
56375597088cSDongdong Hao return true;
56385597088cSDongdong Hao }
56395597088cSDongdong Hao
leapraid_complete_task(struct leapraid_adapter * adapter,u16 taskid,u8 msix_idx,u32 rep)56405597088cSDongdong Hao static void leapraid_complete_task(struct leapraid_adapter *adapter,
56415597088cSDongdong Hao u16 taskid, u8 msix_idx, u32 rep)
56425597088cSDongdong Hao {
56435597088cSDongdong Hao bool scsiio_task = taskid <= adapter->shost->can_queue;
56445597088cSDongdong Hao
56455597088cSDongdong Hao if (scsiio_task) {
56465597088cSDongdong Hao if (leapraid_scsiio_done(adapter, taskid, msix_idx, rep))
56475597088cSDongdong Hao leapraid_free_taskid(adapter, taskid);
56485597088cSDongdong Hao return;
56495597088cSDongdong Hao }
56505597088cSDongdong Hao
56515597088cSDongdong Hao if (leapraid_driver_cmds_done(adapter, taskid, msix_idx, rep,
56525597088cSDongdong Hao leapraid_get_cb_idx(adapter, taskid)))
56535597088cSDongdong Hao leapraid_free_taskid(adapter, taskid);
56545597088cSDongdong Hao }
56555597088cSDongdong Hao
leapraid_request_descript_handler(struct leapraid_adapter * adapter,union leapraid_rep_desc_union * rpf,u8 req_desc_type,u8 msix_idx)56565597088cSDongdong Hao static void leapraid_request_descript_handler(
56575597088cSDongdong Hao struct leapraid_adapter *adapter,
56585597088cSDongdong Hao union leapraid_rep_desc_union *rpf,
56595597088cSDongdong Hao u8 req_desc_type, u8 msix_idx)
56605597088cSDongdong Hao {
56615597088cSDongdong Hao u32 rep;
56625597088cSDongdong Hao u16 taskid;
56635597088cSDongdong Hao
56645597088cSDongdong Hao rep = 0;
56655597088cSDongdong Hao taskid = le16_to_cpu(rpf->dflt_rep.taskid);
56665597088cSDongdong Hao switch (req_desc_type) {
56675597088cSDongdong Hao case LEAPRAID_RPY_DESC_FLG_FP_SCSI_IO_SUCCESS:
56685597088cSDongdong Hao case LEAPRAID_RPY_DESC_FLG_SCSI_IO_SUCCESS:
56695597088cSDongdong Hao leapraid_complete_task(adapter, taskid, msix_idx, 0);
56705597088cSDongdong Hao break;
56715597088cSDongdong Hao case LEAPRAID_RPY_DESC_FLG_ADDRESS_REPLY:
56725597088cSDongdong Hao rep = le32_to_cpu(rpf->addr_rep.rep_frame_addr);
56735597088cSDongdong Hao if (rep > (u32)adapter->mem_desc.rep_msg_dma +
56745597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd *
56755597088cSDongdong Hao LEAPRAID_REPLY_SIZE ||
56765597088cSDongdong Hao rep < (u32)adapter->mem_desc.rep_msg_dma)
56775597088cSDongdong Hao rep = 0;
56785597088cSDongdong Hao
56795597088cSDongdong Hao if (taskid)
56805597088cSDongdong Hao leapraid_complete_task(adapter, taskid, msix_idx, rep);
56815597088cSDongdong Hao else
56825597088cSDongdong Hao leapraid_handle_async_event(adapter, msix_idx, rep);
56835597088cSDongdong Hao
56845597088cSDongdong Hao if (!rep)
56855597088cSDongdong Hao return;
56865597088cSDongdong Hao
56875597088cSDongdong Hao adapter->rep_msg_host_idx =
56885597088cSDongdong Hao (adapter->rep_msg_host_idx ==
56895597088cSDongdong Hao (adapter->adapter_attr.rep_msg_qd - 1)) ?
56905597088cSDongdong Hao 0 : adapter->rep_msg_host_idx + 1;
56915597088cSDongdong Hao adapter->mem_desc.rep_msg_addr[adapter->rep_msg_host_idx] =
56925597088cSDongdong Hao cpu_to_le32(rep);
56935597088cSDongdong Hao wmb(); /* Make sure that all write ops are in order */
56945597088cSDongdong Hao writel(adapter->rep_msg_host_idx,
56955597088cSDongdong Hao &adapter->iomem_base->rep_msg_host_idx);
56965597088cSDongdong Hao
56975597088cSDongdong Hao break;
56985597088cSDongdong Hao default:
56995597088cSDongdong Hao break;
57005597088cSDongdong Hao }
57015597088cSDongdong Hao }
57025597088cSDongdong Hao
leapraid_rep_queue_handler(struct leapraid_rq * rq)57035597088cSDongdong Hao int leapraid_rep_queue_handler(struct leapraid_rq *rq)
57045597088cSDongdong Hao {
57055597088cSDongdong Hao struct leapraid_adapter *adapter = rq->adapter;
57065597088cSDongdong Hao union leapraid_rep_desc_union *rep_desc;
57075597088cSDongdong Hao u8 req_desc_type;
57085597088cSDongdong Hao u64 finish_cmds;
57095597088cSDongdong Hao u8 msix_idx;
57105597088cSDongdong Hao
57115597088cSDongdong Hao msix_idx = rq->msix_idx;
57125597088cSDongdong Hao finish_cmds = 0;
57135597088cSDongdong Hao if (!atomic_add_unless(&rq->busy, LEAPRAID_BUSY_LIMIT,
57145597088cSDongdong Hao LEAPRAID_BUSY_LIMIT))
57155597088cSDongdong Hao return finish_cmds;
57165597088cSDongdong Hao
57175597088cSDongdong Hao rep_desc = &rq->rep_desc[rq->rep_post_host_idx];
57185597088cSDongdong Hao req_desc_type = rep_desc->dflt_rep.rep_flg &
57195597088cSDongdong Hao LEAPRAID_RPY_DESC_FLG_TYPE_MASK;
57205597088cSDongdong Hao if (req_desc_type == LEAPRAID_RPY_DESC_FLG_UNUSED) {
57215597088cSDongdong Hao atomic_dec(&rq->busy);
57225597088cSDongdong Hao return finish_cmds;
57235597088cSDongdong Hao }
57245597088cSDongdong Hao
57255597088cSDongdong Hao for (;;) {
57265597088cSDongdong Hao if (rep_desc->u.low == UINT_MAX ||
57275597088cSDongdong Hao rep_desc->u.high == UINT_MAX)
57285597088cSDongdong Hao break;
57295597088cSDongdong Hao
57305597088cSDongdong Hao leapraid_request_descript_handler(adapter, rep_desc,
57315597088cSDongdong Hao req_desc_type, msix_idx);
57325597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
57335597088cSDongdong Hao "LEAPRAID_SCSIIO: Handled Desc taskid %d, msix %d\n",
57345597088cSDongdong Hao rep_desc->dflt_rep.taskid, msix_idx);
57355597088cSDongdong Hao rep_desc->words = cpu_to_le64(ULLONG_MAX);
57365597088cSDongdong Hao rq->rep_post_host_idx =
57375597088cSDongdong Hao (rq->rep_post_host_idx ==
57385597088cSDongdong Hao (adapter->adapter_attr.rep_desc_qd -
57395597088cSDongdong Hao LEAPRAID_BUSY_LIMIT)) ?
57405597088cSDongdong Hao 0 : rq->rep_post_host_idx + 1;
57415597088cSDongdong Hao req_desc_type =
57425597088cSDongdong Hao rq->rep_desc[rq->rep_post_host_idx].dflt_rep.rep_flg &
57435597088cSDongdong Hao LEAPRAID_RPY_DESC_FLG_TYPE_MASK;
57445597088cSDongdong Hao finish_cmds++;
57455597088cSDongdong Hao if (req_desc_type == LEAPRAID_RPY_DESC_FLG_UNUSED)
57465597088cSDongdong Hao break;
57475597088cSDongdong Hao rep_desc = rq->rep_desc + rq->rep_post_host_idx;
57485597088cSDongdong Hao }
57495597088cSDongdong Hao
57505597088cSDongdong Hao if (!finish_cmds) {
57515597088cSDongdong Hao atomic_dec(&rq->busy);
57525597088cSDongdong Hao return finish_cmds;
57535597088cSDongdong Hao }
57545597088cSDongdong Hao
57555597088cSDongdong Hao wmb(); /* Make sure that all write ops are in order */
57565597088cSDongdong Hao writel(rq->rep_post_host_idx | ((msix_idx & LEAPRAID_MSIX_GROUP_MASK) <<
57575597088cSDongdong Hao LEAPRAID_RPHI_MSIX_IDX_SHIFT),
57585597088cSDongdong Hao &adapter->iomem_base->rep_post_reg_idx[
57595597088cSDongdong Hao msix_idx / LEAPRAID_MSIX_GROUP_SIZE].idx);
57605597088cSDongdong Hao atomic_dec(&rq->busy);
57615597088cSDongdong Hao return finish_cmds;
57625597088cSDongdong Hao }
57635597088cSDongdong Hao
leapraid_irq_handler(int irq,void * bus_id)57645597088cSDongdong Hao static irqreturn_t leapraid_irq_handler(int irq, void *bus_id)
57655597088cSDongdong Hao {
57665597088cSDongdong Hao struct leapraid_rq *rq = bus_id;
57675597088cSDongdong Hao struct leapraid_adapter *adapter = rq->adapter;
57685597088cSDongdong Hao
57695597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
57705597088cSDongdong Hao "LEAPRAID_SCSIIO: Receive a interrupt, irq %d msix %d\n",
57715597088cSDongdong Hao irq, rq->msix_idx);
57725597088cSDongdong Hao
57735597088cSDongdong Hao if (adapter->mask_int)
57745597088cSDongdong Hao return IRQ_NONE;
57755597088cSDongdong Hao
57765597088cSDongdong Hao return (leapraid_rep_queue_handler(rq) > 0 ?
57775597088cSDongdong Hao IRQ_HANDLED : IRQ_NONE);
57785597088cSDongdong Hao }
57795597088cSDongdong Hao
leapraid_sync_irqs(struct leapraid_adapter * adapter,bool poll)57805597088cSDongdong Hao void leapraid_sync_irqs(struct leapraid_adapter *adapter, bool poll)
57815597088cSDongdong Hao {
57825597088cSDongdong Hao struct leapraid_int_rq *int_rq;
57835597088cSDongdong Hao struct leapraid_blk_mq_poll_rq *blk_mq_poll_rq;
57845597088cSDongdong Hao unsigned int i;
57855597088cSDongdong Hao
57865597088cSDongdong Hao if (!adapter->notification_desc.msix_enable)
57875597088cSDongdong Hao return;
57885597088cSDongdong Hao
57895597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
57905597088cSDongdong Hao adapter->access_ctrl.host_removing ||
57915597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
57925597088cSDongdong Hao return;
57935597088cSDongdong Hao
57945597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qdex; i++) {
57955597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[i];
57965597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
57975597088cSDongdong Hao adapter->access_ctrl.host_removing ||
57985597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
57995597088cSDongdong Hao return;
58005597088cSDongdong Hao
58015597088cSDongdong Hao if (int_rq->rq.msix_idx == 0)
58025597088cSDongdong Hao continue;
58035597088cSDongdong Hao
58045597088cSDongdong Hao synchronize_irq(pci_irq_vector(adapter->pdev,
58055597088cSDongdong Hao int_rq->rq.msix_idx));
58065597088cSDongdong Hao if (poll)
58075597088cSDongdong Hao leapraid_rep_queue_handler(&int_rq->rq);
58085597088cSDongdong Hao }
58095597088cSDongdong Hao
58105597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qcnt; i++) {
58115597088cSDongdong Hao blk_mq_poll_rq =
58125597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i];
58135597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering ||
58145597088cSDongdong Hao adapter->access_ctrl.host_removing ||
58155597088cSDongdong Hao adapter->access_ctrl.pcie_recovering)
58165597088cSDongdong Hao return;
58175597088cSDongdong Hao
58185597088cSDongdong Hao if (blk_mq_poll_rq->rq.msix_idx == 0)
58195597088cSDongdong Hao continue;
58205597088cSDongdong Hao
58215597088cSDongdong Hao leapraid_rep_queue_handler(&blk_mq_poll_rq->rq);
58225597088cSDongdong Hao }
58235597088cSDongdong Hao }
58245597088cSDongdong Hao
leapraid_sync_irqs_for_cleanup(struct leapraid_adapter * adapter)58255597088cSDongdong Hao static void leapraid_sync_irqs_for_cleanup(struct leapraid_adapter *adapter)
58265597088cSDongdong Hao {
58275597088cSDongdong Hao struct leapraid_notification_desc *desc = &adapter->notification_desc;
58285597088cSDongdong Hao struct leapraid_int_rq *int_rq;
58295597088cSDongdong Hao unsigned int i;
58305597088cSDongdong Hao
58315597088cSDongdong Hao if (!adapter->mask_int && leapraid_pci_active(adapter))
58325597088cSDongdong Hao leapraid_mask_int(adapter);
58335597088cSDongdong Hao
58345597088cSDongdong Hao for (i = 0; i < desc->int_rqs_allocated; i++) {
58355597088cSDongdong Hao int_rq = &desc->int_rqs[i];
58365597088cSDongdong Hao synchronize_irq(pci_irq_vector(adapter->pdev,
58375597088cSDongdong Hao int_rq->rq.msix_idx));
58385597088cSDongdong Hao }
58395597088cSDongdong Hao }
58405597088cSDongdong Hao
leapraid_mq_polling_pause(struct leapraid_adapter * adapter)58415597088cSDongdong Hao void leapraid_mq_polling_pause(struct leapraid_adapter *adapter)
58425597088cSDongdong Hao {
58435597088cSDongdong Hao struct leapraid_notification_desc *desc;
58445597088cSDongdong Hao int iopoll_q_count;
58455597088cSDongdong Hao int qid;
58465597088cSDongdong Hao
58475597088cSDongdong Hao desc = &adapter->notification_desc;
58485597088cSDongdong Hao iopoll_q_count = adapter->adapter_attr.rq_cnt - desc->iopoll_qdex;
58495597088cSDongdong Hao
58505597088cSDongdong Hao for (qid = 0; qid < iopoll_q_count; qid++)
58515597088cSDongdong Hao atomic_set(&desc->blk_mq_poll_rqs[qid].pause, 1);
58525597088cSDongdong Hao
58535597088cSDongdong Hao for (qid = 0; qid < iopoll_q_count; qid++) {
58545597088cSDongdong Hao while (atomic_read(&desc->blk_mq_poll_rqs[qid].busy)) {
58555597088cSDongdong Hao cpu_relax();
58565597088cSDongdong Hao udelay(LEAPRAID_IO_POLL_DELAY_US);
58575597088cSDongdong Hao }
58585597088cSDongdong Hao }
58595597088cSDongdong Hao }
58605597088cSDongdong Hao
leapraid_mq_polling_resume(struct leapraid_adapter * adapter)58615597088cSDongdong Hao void leapraid_mq_polling_resume(struct leapraid_adapter *adapter)
58625597088cSDongdong Hao {
58635597088cSDongdong Hao struct leapraid_notification_desc *desc;
58645597088cSDongdong Hao int iopoll_q_count;
58655597088cSDongdong Hao int qid;
58665597088cSDongdong Hao
58675597088cSDongdong Hao desc = &adapter->notification_desc;
58685597088cSDongdong Hao iopoll_q_count = adapter->adapter_attr.rq_cnt - desc->iopoll_qdex;
58695597088cSDongdong Hao
58705597088cSDongdong Hao for (qid = 0; qid < iopoll_q_count; qid++)
58715597088cSDongdong Hao atomic_set(&desc->blk_mq_poll_rqs[qid].pause, 0);
58725597088cSDongdong Hao }
58735597088cSDongdong Hao
leapraid_unlock_host_diag(struct leapraid_adapter * adapter,u32 * host_diag)58745597088cSDongdong Hao static int leapraid_unlock_host_diag(struct leapraid_adapter *adapter,
58755597088cSDongdong Hao u32 *host_diag)
58765597088cSDongdong Hao {
58775597088cSDongdong Hao const u32 unlock_seq[] = {
58785597088cSDongdong Hao LEAPRAID_WRSEQ_FLUSH_KEY_VALUE,
58795597088cSDongdong Hao LEAPRAID_WRSEQ_1ST_KEY_VALUE,
58805597088cSDongdong Hao LEAPRAID_WRSEQ_2ND_KEY_VALUE,
58815597088cSDongdong Hao LEAPRAID_WRSEQ_3RD_KEY_VALUE,
58825597088cSDongdong Hao LEAPRAID_WRSEQ_4TH_KEY_VALUE,
58835597088cSDongdong Hao LEAPRAID_WRSEQ_5TH_KEY_VALUE,
58845597088cSDongdong Hao LEAPRAID_WRSEQ_6TH_KEY_VALUE
58855597088cSDongdong Hao };
58865597088cSDongdong Hao
58875597088cSDongdong Hao const int max_retries = LEAPRAID_UNLOCK_RETRY_LIMIT;
58885597088cSDongdong Hao int retry = 0;
58895597088cSDongdong Hao unsigned int i;
58905597088cSDongdong Hao
58915597088cSDongdong Hao *host_diag = 0;
58925597088cSDongdong Hao while (retry++ <= max_retries) {
58935597088cSDongdong Hao for (i = 0; i < ARRAY_SIZE(unlock_seq); i++)
58945597088cSDongdong Hao writel(unlock_seq[i], &adapter->iomem_base->ws);
58955597088cSDongdong Hao
58965597088cSDongdong Hao msleep(LEAPRAID_UNLOCK_SLEEP_MS);
58975597088cSDongdong Hao
58985597088cSDongdong Hao *host_diag = leapraid_readl(&adapter->iomem_base->host_diag);
58995597088cSDongdong Hao if (*host_diag & LEAPRAID_DIAG_WRITE_ENABLE)
59005597088cSDongdong Hao return 0;
59015597088cSDongdong Hao }
59025597088cSDongdong Hao
59035597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Try host reset timeout!\n");
59045597088cSDongdong Hao return -EFAULT;
59055597088cSDongdong Hao }
59065597088cSDongdong Hao
leapraid_host_diag_reset(struct leapraid_adapter * adapter)59075597088cSDongdong Hao static int leapraid_host_diag_reset(struct leapraid_adapter *adapter)
59085597088cSDongdong Hao {
59095597088cSDongdong Hao u32 host_diag;
59105597088cSDongdong Hao
59115597088cSDongdong Hao pci_cfg_access_lock(adapter->pdev);
59125597088cSDongdong Hao
59135597088cSDongdong Hao mutex_lock(&adapter->reset_desc.host_diag_mutex);
59145597088cSDongdong Hao if (leapraid_unlock_host_diag(adapter, &host_diag))
59155597088cSDongdong Hao goto out_cleanup;
59165597088cSDongdong Hao
59175597088cSDongdong Hao writel(host_diag | LEAPRAID_DIAG_RESET,
59185597088cSDongdong Hao &adapter->iomem_base->host_diag);
59195597088cSDongdong Hao
59205597088cSDongdong Hao msleep(LEAPRAID_MSLEEP_EXTRA_LONG_MS);
59215597088cSDongdong Hao msleep(LEAPRAID_MSLEEP_NORMAL_MS);
59225597088cSDongdong Hao
59235597088cSDongdong Hao host_diag = leapraid_readl(&adapter->iomem_base->host_diag);
59245597088cSDongdong Hao if (host_diag == LEAPRAID_INVALID_HOST_DIAG_VAL ||
59255597088cSDongdong Hao host_diag & LEAPRAID_DIAG_RESET)
59265597088cSDongdong Hao goto out_cleanup;
59275597088cSDongdong Hao
59285597088cSDongdong Hao writel(0x0, &adapter->iomem_base->ws);
59295597088cSDongdong Hao mutex_unlock(&adapter->reset_desc.host_diag_mutex);
59305597088cSDongdong Hao if (!leapraid_wait_adapter_ready(adapter))
59315597088cSDongdong Hao goto out_failed;
59325597088cSDongdong Hao
59335597088cSDongdong Hao pci_cfg_access_unlock(adapter->pdev);
59345597088cSDongdong Hao return 0;
59355597088cSDongdong Hao
59365597088cSDongdong Hao out_cleanup:
59375597088cSDongdong Hao mutex_unlock(&adapter->reset_desc.host_diag_mutex);
59385597088cSDongdong Hao out_failed:
59395597088cSDongdong Hao pci_cfg_access_unlock(adapter->pdev);
59405597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Host diag failed\n");
59415597088cSDongdong Hao return -EFAULT;
59425597088cSDongdong Hao }
59435597088cSDongdong Hao
leapraid_find_matching_port(struct leapraid_card_port * card_port_table,u8 count,u8 port_id,u64 sas_addr)59445597088cSDongdong Hao static int leapraid_find_matching_port(
59455597088cSDongdong Hao struct leapraid_card_port *card_port_table,
59465597088cSDongdong Hao u8 count, u8 port_id, u64 sas_addr)
59475597088cSDongdong Hao {
59485597088cSDongdong Hao int i;
59495597088cSDongdong Hao
59505597088cSDongdong Hao for (i = 0; i < count; i++)
59515597088cSDongdong Hao if (card_port_table[i].port_id == port_id &&
59525597088cSDongdong Hao card_port_table[i].sas_address == sas_addr)
59535597088cSDongdong Hao return i;
59545597088cSDongdong Hao
59555597088cSDongdong Hao return LEAPRAID_INVALID_INDEX;
59565597088cSDongdong Hao }
59575597088cSDongdong Hao
leapraid_fill_card_port_table(struct leapraid_adapter * adapter,struct leapraid_sas_io_unit_p0 * sas_iounit_p0,struct leapraid_card_port * new_card_port_table)59585597088cSDongdong Hao static u8 leapraid_fill_card_port_table(
59595597088cSDongdong Hao struct leapraid_adapter *adapter,
59605597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_iounit_p0,
59615597088cSDongdong Hao struct leapraid_card_port *new_card_port_table)
59625597088cSDongdong Hao {
59635597088cSDongdong Hao u8 port_entry_num = 0, port_id;
59645597088cSDongdong Hao u16 attached_hdl;
59655597088cSDongdong Hao u64 attached_sas_addr;
59665597088cSDongdong Hao int i, idx;
59675597088cSDongdong Hao
59685597088cSDongdong Hao for (i = 0; i < adapter->dev_topo.card.phys_num; i++) {
59695597088cSDongdong Hao if (sas_iounit_p0->phy_info[i].neg_link_rate >>
59705597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT <
59715597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5)
59725597088cSDongdong Hao continue;
59735597088cSDongdong Hao
59745597088cSDongdong Hao attached_hdl = le16_to_cpu(sas_iounit_p0->phy_info[i]
59755597088cSDongdong Hao .attached_dev_hdl);
59765597088cSDongdong Hao if (leapraid_get_sas_address(adapter,
59775597088cSDongdong Hao attached_hdl,
59785597088cSDongdong Hao &attached_sas_addr) != 0)
59795597088cSDongdong Hao continue;
59805597088cSDongdong Hao
59815597088cSDongdong Hao port_id = sas_iounit_p0->phy_info[i].port;
59825597088cSDongdong Hao
59835597088cSDongdong Hao idx = leapraid_find_matching_port(new_card_port_table,
59845597088cSDongdong Hao port_entry_num,
59855597088cSDongdong Hao port_id,
59865597088cSDongdong Hao attached_sas_addr);
59875597088cSDongdong Hao if (idx >= 0) {
59885597088cSDongdong Hao new_card_port_table[idx].phy_mask |= BIT(i);
59895597088cSDongdong Hao } else {
59905597088cSDongdong Hao new_card_port_table[port_entry_num].port_id = port_id;
59915597088cSDongdong Hao new_card_port_table[port_entry_num].phy_mask = BIT(i);
59925597088cSDongdong Hao new_card_port_table[port_entry_num].sas_address =
59935597088cSDongdong Hao attached_sas_addr;
59945597088cSDongdong Hao port_entry_num++;
59955597088cSDongdong Hao }
59965597088cSDongdong Hao }
59975597088cSDongdong Hao
59985597088cSDongdong Hao return port_entry_num;
59995597088cSDongdong Hao }
60005597088cSDongdong Hao
leapraid_set_new_card_port_table_after_reset(struct leapraid_adapter * adapter,struct leapraid_card_port * new_card_port_table)60015597088cSDongdong Hao static u8 leapraid_set_new_card_port_table_after_reset(
60025597088cSDongdong Hao struct leapraid_adapter *adapter,
60035597088cSDongdong Hao struct leapraid_card_port *new_card_port_table)
60045597088cSDongdong Hao {
60055597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
60065597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
60075597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_iounit_p0;
60085597088cSDongdong Hao u8 port_entry_num = 0;
60095597088cSDongdong Hao u16 sz;
60105597088cSDongdong Hao
60115597088cSDongdong Hao sz = offsetof(struct leapraid_sas_io_unit_p0, phy_info) +
60125597088cSDongdong Hao (adapter->dev_topo.card.phys_num *
60135597088cSDongdong Hao sizeof(struct leapraid_sas_io_unit0_phy_info));
60145597088cSDongdong Hao sas_iounit_p0 = kzalloc(sz, GFP_KERNEL);
60155597088cSDongdong Hao if (!sas_iounit_p0)
60165597088cSDongdong Hao return port_entry_num;
60175597088cSDongdong Hao
60185597088cSDongdong Hao cfgp1.size = sz;
60195597088cSDongdong Hao if (leapraid_op_config_page(adapter, sas_iounit_p0, cfgp1, cfgp2,
60205597088cSDongdong Hao GET_SAS_IOUNIT_PG0) != 0)
60215597088cSDongdong Hao goto out_free;
60225597088cSDongdong Hao
60235597088cSDongdong Hao port_entry_num = leapraid_fill_card_port_table(adapter,
60245597088cSDongdong Hao sas_iounit_p0,
60255597088cSDongdong Hao new_card_port_table);
60265597088cSDongdong Hao out_free:
60275597088cSDongdong Hao kfree(sas_iounit_p0);
60285597088cSDongdong Hao return port_entry_num;
60295597088cSDongdong Hao }
60305597088cSDongdong Hao
leapraid_update_existing_port(struct leapraid_adapter * adapter,struct leapraid_card_port * new_table,int entry_idx,int port_entry_num)60315597088cSDongdong Hao static void leapraid_update_existing_port(struct leapraid_adapter *adapter,
60325597088cSDongdong Hao struct leapraid_card_port *new_table,
60335597088cSDongdong Hao int entry_idx, int port_entry_num)
60345597088cSDongdong Hao {
60355597088cSDongdong Hao struct leapraid_card_port *matched_card_port;
60365597088cSDongdong Hao int matched_code;
60375597088cSDongdong Hao int count, lcount = 0;
60385597088cSDongdong Hao u64 sas_addr;
60395597088cSDongdong Hao int i;
60405597088cSDongdong Hao
60415597088cSDongdong Hao matched_code = leapraid_check_card_port(adapter,
60425597088cSDongdong Hao &new_table[entry_idx],
60435597088cSDongdong Hao &matched_card_port,
60445597088cSDongdong Hao &count);
60455597088cSDongdong Hao
60465597088cSDongdong Hao if (!matched_card_port)
60475597088cSDongdong Hao return;
60485597088cSDongdong Hao
60495597088cSDongdong Hao if (matched_code == SAME_PORT_WITH_PARTIALLY_CHANGED_PHYS ||
60505597088cSDongdong Hao matched_code == SAME_ADDR_WITH_PARTIALLY_CHANGED_PHYS) {
60515597088cSDongdong Hao leapraid_add_or_del_phys_from_existing_port(adapter,
60525597088cSDongdong Hao matched_card_port,
60535597088cSDongdong Hao new_table,
60545597088cSDongdong Hao entry_idx,
60555597088cSDongdong Hao port_entry_num);
60565597088cSDongdong Hao } else if (matched_code == SAME_ADDR_ONLY) {
60575597088cSDongdong Hao sas_addr = new_table[entry_idx].sas_address;
60585597088cSDongdong Hao for (i = 0; i < port_entry_num; i++)
60595597088cSDongdong Hao if (new_table[i].sas_address == sas_addr)
60605597088cSDongdong Hao lcount++;
60615597088cSDongdong Hao
60625597088cSDongdong Hao if (count > 1 || lcount > 1)
60635597088cSDongdong Hao return;
60645597088cSDongdong Hao
60655597088cSDongdong Hao leapraid_add_or_del_phys_from_existing_port(adapter,
60665597088cSDongdong Hao matched_card_port,
60675597088cSDongdong Hao new_table,
60685597088cSDongdong Hao entry_idx,
60695597088cSDongdong Hao port_entry_num);
60705597088cSDongdong Hao }
60715597088cSDongdong Hao
60725597088cSDongdong Hao if (matched_card_port->port_id != new_table[entry_idx].port_id)
60735597088cSDongdong Hao matched_card_port->port_id = new_table[entry_idx].port_id;
60745597088cSDongdong Hao
60755597088cSDongdong Hao matched_card_port->flg &= ~LEAPRAID_CARD_PORT_FLG_DIRTY;
60765597088cSDongdong Hao matched_card_port->phy_mask = new_table[entry_idx].phy_mask;
60775597088cSDongdong Hao }
60785597088cSDongdong Hao
leapraid_update_card_port_after_reset(struct leapraid_adapter * adapter)60795597088cSDongdong Hao static void leapraid_update_card_port_after_reset(
60805597088cSDongdong Hao struct leapraid_adapter *adapter)
60815597088cSDongdong Hao {
60825597088cSDongdong Hao struct leapraid_card_port *new_card_port_table;
60835597088cSDongdong Hao struct leapraid_card_port *matched_card_port;
60845597088cSDongdong Hao u8 port_entry_num;
60855597088cSDongdong Hao u8 nr_phys;
60865597088cSDongdong Hao int i;
60875597088cSDongdong Hao
60885597088cSDongdong Hao if (leapraid_get_adapter_phys(adapter, &nr_phys) || !nr_phys)
60895597088cSDongdong Hao return;
60905597088cSDongdong Hao
60915597088cSDongdong Hao if (!adapter->dev_topo.card.card_phy) {
60925597088cSDongdong Hao adapter->dev_topo.card.card_phy =
60935597088cSDongdong Hao kcalloc(nr_phys, sizeof(struct leapraid_card_phy),
60945597088cSDongdong Hao GFP_KERNEL);
60955597088cSDongdong Hao if (!adapter->dev_topo.card.card_phy)
60965597088cSDongdong Hao return;
60975597088cSDongdong Hao }
60985597088cSDongdong Hao
60995597088cSDongdong Hao adapter->dev_topo.card.phys_num = nr_phys;
61005597088cSDongdong Hao
61015597088cSDongdong Hao new_card_port_table = kcalloc(adapter->dev_topo.card.phys_num,
61025597088cSDongdong Hao sizeof(struct leapraid_card_port),
61035597088cSDongdong Hao GFP_KERNEL);
61045597088cSDongdong Hao if (!new_card_port_table)
61055597088cSDongdong Hao return;
61065597088cSDongdong Hao
61075597088cSDongdong Hao port_entry_num =
61085597088cSDongdong Hao leapraid_set_new_card_port_table_after_reset(
61095597088cSDongdong Hao adapter,
61105597088cSDongdong Hao new_card_port_table);
61115597088cSDongdong Hao if (!port_entry_num)
61125597088cSDongdong Hao goto out_free_port_table;
61135597088cSDongdong Hao
61145597088cSDongdong Hao list_for_each_entry(matched_card_port,
61155597088cSDongdong Hao &adapter->dev_topo.card_port_list, list)
61165597088cSDongdong Hao matched_card_port->flg |= LEAPRAID_CARD_PORT_FLG_DIRTY;
61175597088cSDongdong Hao
61185597088cSDongdong Hao matched_card_port = NULL;
61195597088cSDongdong Hao for (i = 0; i < port_entry_num; i++)
61205597088cSDongdong Hao leapraid_update_existing_port(adapter,
61215597088cSDongdong Hao new_card_port_table,
61225597088cSDongdong Hao i, port_entry_num);
61235597088cSDongdong Hao out_free_port_table:
61245597088cSDongdong Hao kfree(new_card_port_table);
61255597088cSDongdong Hao }
61265597088cSDongdong Hao
leapraid_is_valid_vphy(struct leapraid_adapter * adapter,struct leapraid_sas_io_unit_p0 * sas_io_unit_p0,int phy_index)61275597088cSDongdong Hao static bool leapraid_is_valid_vphy(
61285597088cSDongdong Hao struct leapraid_adapter *adapter,
61295597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_io_unit_p0,
61305597088cSDongdong Hao int phy_index)
61315597088cSDongdong Hao {
61325597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
61335597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
61345597088cSDongdong Hao struct leapraid_sas_phy_p0 phy_p0;
61355597088cSDongdong Hao u32 dev_info;
61365597088cSDongdong Hao
61375597088cSDongdong Hao if (sas_io_unit_p0->phy_info[phy_index].neg_link_rate >>
61385597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT <
61395597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5)
61405597088cSDongdong Hao return false;
61415597088cSDongdong Hao
61425597088cSDongdong Hao dev_info = le32_to_cpu(sas_io_unit_p0->phy_info[phy_index]
61435597088cSDongdong Hao .controller_phy_dev_info);
61445597088cSDongdong Hao if (!(dev_info & LEAPRAID_DEVTYP_SEP))
61455597088cSDongdong Hao return false;
61465597088cSDongdong Hao
61475597088cSDongdong Hao cfgp1.phy_number = phy_index;
61485597088cSDongdong Hao if (leapraid_op_config_page(adapter, &phy_p0, cfgp1, cfgp2,
61495597088cSDongdong Hao GET_PHY_PG0))
61505597088cSDongdong Hao return false;
61515597088cSDongdong Hao
61525597088cSDongdong Hao if (!(le32_to_cpu(phy_p0.phy_info) & LEAPRAID_SAS_PHYINFO_VPHY))
61535597088cSDongdong Hao return false;
61545597088cSDongdong Hao
61555597088cSDongdong Hao return true;
61565597088cSDongdong Hao }
61575597088cSDongdong Hao
leapraid_update_vphy_binding(struct leapraid_adapter * adapter,struct leapraid_card_port * card_port,struct leapraid_vphy * vphy,int phy_index,u8 may_new_port_id,u64 attached_sas_addr)61585597088cSDongdong Hao static void leapraid_update_vphy_binding(struct leapraid_adapter *adapter,
61595597088cSDongdong Hao struct leapraid_card_port *card_port,
61605597088cSDongdong Hao struct leapraid_vphy *vphy,
61615597088cSDongdong Hao int phy_index, u8 may_new_port_id,
61625597088cSDongdong Hao u64 attached_sas_addr)
61635597088cSDongdong Hao {
61645597088cSDongdong Hao struct leapraid_card_port *may_new_card_port;
61655597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
61665597088cSDongdong Hao
61675597088cSDongdong Hao may_new_card_port = leapraid_get_port_by_id(adapter,
61685597088cSDongdong Hao may_new_port_id,
61695597088cSDongdong Hao true);
61705597088cSDongdong Hao if (!may_new_card_port) {
61715597088cSDongdong Hao may_new_card_port = kzalloc_obj(*may_new_card_port);
61725597088cSDongdong Hao if (!may_new_card_port)
61735597088cSDongdong Hao return;
61745597088cSDongdong Hao may_new_card_port->port_id = may_new_port_id;
61755597088cSDongdong Hao dev_err(&adapter->pdev->dev,
61765597088cSDongdong Hao "%s: New card port %p added, port=%d\n",
61775597088cSDongdong Hao __func__, may_new_card_port, may_new_port_id);
61785597088cSDongdong Hao list_add_tail(&may_new_card_port->list,
61795597088cSDongdong Hao &adapter->dev_topo.card_port_list);
61805597088cSDongdong Hao }
61815597088cSDongdong Hao
61825597088cSDongdong Hao if (card_port != may_new_card_port) {
61835597088cSDongdong Hao if (!may_new_card_port->vphys_mask)
61845597088cSDongdong Hao INIT_LIST_HEAD(&may_new_card_port->vphys_list);
61855597088cSDongdong Hao may_new_card_port->vphys_mask |= BIT(phy_index);
61865597088cSDongdong Hao card_port->vphys_mask &= ~BIT(phy_index);
61875597088cSDongdong Hao list_move(&vphy->list, &may_new_card_port->vphys_list);
61885597088cSDongdong Hao
61895597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_addr(adapter,
61905597088cSDongdong Hao attached_sas_addr,
61915597088cSDongdong Hao card_port);
61925597088cSDongdong Hao if (sas_dev) {
61935597088cSDongdong Hao sas_dev->card_port = may_new_card_port;
61945597088cSDongdong Hao leapraid_sdev_put(sas_dev);
61955597088cSDongdong Hao }
61965597088cSDongdong Hao }
61975597088cSDongdong Hao
61985597088cSDongdong Hao if (may_new_card_port->flg & LEAPRAID_CARD_PORT_FLG_DIRTY) {
61995597088cSDongdong Hao may_new_card_port->sas_address = 0;
62005597088cSDongdong Hao may_new_card_port->phy_mask = 0;
62015597088cSDongdong Hao may_new_card_port->flg &= ~LEAPRAID_CARD_PORT_FLG_DIRTY;
62025597088cSDongdong Hao }
62035597088cSDongdong Hao vphy->flg &= ~LEAPRAID_VPHY_FLG_DIRTY;
62045597088cSDongdong Hao }
62055597088cSDongdong Hao
leapraid_update_vphys_after_reset(struct leapraid_adapter * adapter)62065597088cSDongdong Hao static void leapraid_update_vphys_after_reset(struct leapraid_adapter *adapter)
62075597088cSDongdong Hao {
62085597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
62095597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
62105597088cSDongdong Hao struct leapraid_sas_io_unit_p0 *sas_iounit_p0;
62115597088cSDongdong Hao struct leapraid_card_port *card_port, *card_port_next;
62125597088cSDongdong Hao struct leapraid_vphy *vphy, *vphy_next;
62135597088cSDongdong Hao u64 attached_sas_addr;
62145597088cSDongdong Hao u16 sz;
62155597088cSDongdong Hao u16 attached_hdl;
62165597088cSDongdong Hao bool found = false;
62175597088cSDongdong Hao u8 port_id;
62185597088cSDongdong Hao int i;
62195597088cSDongdong Hao
62205597088cSDongdong Hao list_for_each_entry_safe(card_port, card_port_next,
62215597088cSDongdong Hao &adapter->dev_topo.card_port_list, list) {
62225597088cSDongdong Hao if (!card_port->vphys_mask)
62235597088cSDongdong Hao continue;
62245597088cSDongdong Hao
62255597088cSDongdong Hao list_for_each_entry_safe(vphy, vphy_next,
62265597088cSDongdong Hao &card_port->vphys_list, list)
62275597088cSDongdong Hao vphy->flg |= LEAPRAID_VPHY_FLG_DIRTY;
62285597088cSDongdong Hao }
62295597088cSDongdong Hao
62305597088cSDongdong Hao sz = offsetof(struct leapraid_sas_io_unit_p0, phy_info) +
62315597088cSDongdong Hao (adapter->dev_topo.card.phys_num *
62325597088cSDongdong Hao sizeof(struct leapraid_sas_io_unit0_phy_info));
62335597088cSDongdong Hao sas_iounit_p0 = kzalloc(sz, GFP_KERNEL);
62345597088cSDongdong Hao if (!sas_iounit_p0)
62355597088cSDongdong Hao return;
62365597088cSDongdong Hao
62375597088cSDongdong Hao cfgp1.size = sz;
62385597088cSDongdong Hao if (leapraid_op_config_page(adapter, sas_iounit_p0, cfgp1, cfgp2,
62395597088cSDongdong Hao GET_SAS_IOUNIT_PG0) != 0)
62405597088cSDongdong Hao goto out_free;
62415597088cSDongdong Hao
62425597088cSDongdong Hao for (i = 0; i < adapter->dev_topo.card.phys_num; i++) {
62435597088cSDongdong Hao if (!leapraid_is_valid_vphy(adapter, sas_iounit_p0, i))
62445597088cSDongdong Hao continue;
62455597088cSDongdong Hao
62465597088cSDongdong Hao attached_hdl =
62475597088cSDongdong Hao le16_to_cpu(sas_iounit_p0->phy_info[i]
62485597088cSDongdong Hao .attached_dev_hdl);
62495597088cSDongdong Hao if (leapraid_get_sas_address(adapter, attached_hdl,
62505597088cSDongdong Hao &attached_sas_addr) != 0)
62515597088cSDongdong Hao continue;
62525597088cSDongdong Hao
62535597088cSDongdong Hao found = false;
62545597088cSDongdong Hao card_port = NULL;
62555597088cSDongdong Hao card_port_next = NULL;
62565597088cSDongdong Hao list_for_each_entry_safe(card_port, card_port_next,
62575597088cSDongdong Hao &adapter->dev_topo.card_port_list,
62585597088cSDongdong Hao list) {
62595597088cSDongdong Hao if (!card_port->vphys_mask)
62605597088cSDongdong Hao continue;
62615597088cSDongdong Hao
62625597088cSDongdong Hao list_for_each_entry_safe(vphy, vphy_next,
62635597088cSDongdong Hao &card_port->vphys_list,
62645597088cSDongdong Hao list) {
62655597088cSDongdong Hao if (!(vphy->flg & LEAPRAID_VPHY_FLG_DIRTY))
62665597088cSDongdong Hao continue;
62675597088cSDongdong Hao
62685597088cSDongdong Hao if (vphy->sas_address != attached_sas_addr)
62695597088cSDongdong Hao continue;
62705597088cSDongdong Hao
62715597088cSDongdong Hao if (!(vphy->phy_mask & BIT(i)))
62725597088cSDongdong Hao vphy->phy_mask = BIT(i);
62735597088cSDongdong Hao
62745597088cSDongdong Hao port_id = sas_iounit_p0->phy_info[i].port;
62755597088cSDongdong Hao
62765597088cSDongdong Hao leapraid_update_vphy_binding(adapter,
62775597088cSDongdong Hao card_port,
62785597088cSDongdong Hao vphy,
62795597088cSDongdong Hao i,
62805597088cSDongdong Hao port_id,
62815597088cSDongdong Hao attached_sas_addr);
62825597088cSDongdong Hao
62835597088cSDongdong Hao found = true;
62845597088cSDongdong Hao break;
62855597088cSDongdong Hao }
62865597088cSDongdong Hao if (found)
62875597088cSDongdong Hao break;
62885597088cSDongdong Hao }
62895597088cSDongdong Hao }
62905597088cSDongdong Hao out_free:
62915597088cSDongdong Hao kfree(sas_iounit_p0);
62925597088cSDongdong Hao }
62935597088cSDongdong Hao
leapraid_mark_all_dev_deleted(struct leapraid_adapter * adapter)62945597088cSDongdong Hao static void leapraid_mark_all_dev_deleted(struct leapraid_adapter *adapter)
62955597088cSDongdong Hao {
62965597088cSDongdong Hao struct leapraid_sdev_priv *sdev_priv;
62975597088cSDongdong Hao struct scsi_device *sdev;
62985597088cSDongdong Hao
62995597088cSDongdong Hao shost_for_each_device(sdev, adapter->shost) {
63005597088cSDongdong Hao sdev_priv = sdev->hostdata;
63015597088cSDongdong Hao if (sdev_priv && sdev_priv->starget_priv)
63025597088cSDongdong Hao sdev_priv->starget_priv->deleted = 1;
63035597088cSDongdong Hao }
63045597088cSDongdong Hao }
63055597088cSDongdong Hao
leapraid_free_enc_list(struct leapraid_adapter * adapter)63065597088cSDongdong Hao static void leapraid_free_enc_list(struct leapraid_adapter *adapter)
63075597088cSDongdong Hao {
63085597088cSDongdong Hao struct leapraid_enc_node *enc_dev, *enc_dev_next;
63095597088cSDongdong Hao LIST_HEAD(free_list);
63105597088cSDongdong Hao unsigned long flags;
63115597088cSDongdong Hao
63125597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
63135597088cSDongdong Hao list_splice_init(&adapter->dev_topo.enc_list, &free_list);
63145597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
63155597088cSDongdong Hao
63165597088cSDongdong Hao list_for_each_entry_safe(enc_dev, enc_dev_next, &free_list, list) {
63175597088cSDongdong Hao list_del(&enc_dev->list);
63185597088cSDongdong Hao kfree(enc_dev);
63195597088cSDongdong Hao }
63205597088cSDongdong Hao }
63215597088cSDongdong Hao
leapraid_rebuild_enc_list_after_reset(struct leapraid_adapter * adapter)63225597088cSDongdong Hao static void leapraid_rebuild_enc_list_after_reset(
63235597088cSDongdong Hao struct leapraid_adapter *adapter)
63245597088cSDongdong Hao {
63255597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
63265597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
63275597088cSDongdong Hao struct leapraid_enc_node *enc_node;
63285597088cSDongdong Hao u16 enc_hdl;
63295597088cSDongdong Hao unsigned long flags;
63305597088cSDongdong Hao int rc;
63315597088cSDongdong Hao
63325597088cSDongdong Hao leapraid_free_enc_list(adapter);
63335597088cSDongdong Hao
63345597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
63355597088cSDongdong Hao for (enc_hdl = 0xFFFF; ; enc_hdl = le16_to_cpu(enc_node->pg0.enc_hdl)) {
63365597088cSDongdong Hao enc_node = kzalloc_obj(*enc_node);
63375597088cSDongdong Hao if (!enc_node)
63385597088cSDongdong Hao return;
63395597088cSDongdong Hao
63405597088cSDongdong Hao cfgp2.handle = enc_hdl;
63415597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &enc_node->pg0, cfgp1,
63425597088cSDongdong Hao cfgp2, GET_SAS_ENCLOSURE_PG0);
63435597088cSDongdong Hao if (rc) {
63445597088cSDongdong Hao kfree(enc_node);
63455597088cSDongdong Hao return;
63465597088cSDongdong Hao }
63475597088cSDongdong Hao
63485597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, flags);
63495597088cSDongdong Hao list_add_tail(&enc_node->list, &adapter->dev_topo.enc_list);
63505597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, flags);
63515597088cSDongdong Hao }
63525597088cSDongdong Hao }
63535597088cSDongdong Hao
leapraid_mark_resp_sas_dev(struct leapraid_adapter * adapter,struct leapraid_sas_dev_p0 * sas_dev_p0)63545597088cSDongdong Hao static void leapraid_mark_resp_sas_dev(struct leapraid_adapter *adapter,
63555597088cSDongdong Hao struct leapraid_sas_dev_p0 *sas_dev_p0)
63565597088cSDongdong Hao {
63575597088cSDongdong Hao struct leapraid_starget_priv *starget_priv;
63585597088cSDongdong Hao struct leapraid_enc_node *enc_node = NULL;
63595597088cSDongdong Hao struct leapraid_card_port *card_port;
63605597088cSDongdong Hao struct leapraid_sas_dev *sas_dev;
63615597088cSDongdong Hao struct scsi_target *starget;
63625597088cSDongdong Hao unsigned long flags;
63635597088cSDongdong Hao unsigned long enc_flags = 0;
63645597088cSDongdong Hao u16 enc_hdl;
63655597088cSDongdong Hao u64 enc_lid = 0;
63665597088cSDongdong Hao
63675597088cSDongdong Hao card_port = leapraid_get_port_by_id(adapter, sas_dev_p0->physical_port,
63685597088cSDongdong Hao false);
63695597088cSDongdong Hao enc_hdl = le16_to_cpu(sas_dev_p0->enc_hdl);
63705597088cSDongdong Hao if (enc_hdl) {
63715597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, enc_flags);
63725597088cSDongdong Hao enc_node = leapraid_enc_find_by_hdl(adapter, enc_hdl);
63735597088cSDongdong Hao if (enc_node)
63745597088cSDongdong Hao enc_lid = le64_to_cpu(enc_node->pg0.enc_lid);
63755597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, enc_flags);
63765597088cSDongdong Hao if (!enc_node)
63775597088cSDongdong Hao dev_info(&adapter->pdev->dev,
63785597088cSDongdong Hao "enc hdl 0x%04x has no matched enc dev\n",
63795597088cSDongdong Hao enc_hdl);
63805597088cSDongdong Hao }
63815597088cSDongdong Hao
63825597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
63835597088cSDongdong Hao list_for_each_entry(sas_dev, &adapter->dev_topo.sas_dev_list, list) {
63845597088cSDongdong Hao if (sas_dev->sas_addr != le64_to_cpu(sas_dev_p0->sas_address) ||
63855597088cSDongdong Hao sas_dev->slot != le16_to_cpu(sas_dev_p0->slot) ||
63865597088cSDongdong Hao sas_dev->card_port != card_port)
63875597088cSDongdong Hao continue;
63885597088cSDongdong Hao
63895597088cSDongdong Hao sas_dev->resp = 1;
63905597088cSDongdong Hao starget = sas_dev->starget;
63915597088cSDongdong Hao if (starget && starget->hostdata) {
63925597088cSDongdong Hao starget_priv = starget->hostdata;
63935597088cSDongdong Hao starget_priv->tm_busy = 0;
63945597088cSDongdong Hao starget_priv->deleted = 0;
63955597088cSDongdong Hao } else {
63965597088cSDongdong Hao starget_priv = NULL;
63975597088cSDongdong Hao }
63985597088cSDongdong Hao
63995597088cSDongdong Hao if (starget) {
64005597088cSDongdong Hao starget_printk(
64015597088cSDongdong Hao KERN_INFO, starget,
64025597088cSDongdong Hao "dev: hdl=0x%04x saddr=0x%016llx port_id=%d\n",
64035597088cSDongdong Hao sas_dev->hdl,
64045597088cSDongdong Hao (unsigned long long)sas_dev->sas_addr,
64055597088cSDongdong Hao sas_dev->card_port->port_id);
64065597088cSDongdong Hao if (sas_dev->enc_hdl != 0)
64075597088cSDongdong Hao starget_printk(
64085597088cSDongdong Hao KERN_INFO,
64095597088cSDongdong Hao starget,
64105597088cSDongdong Hao "enc info: enc_lid=0x%016llx slot=%d\n",
64115597088cSDongdong Hao (unsigned long long)sas_dev->enc_lid,
64125597088cSDongdong Hao sas_dev->slot);
64135597088cSDongdong Hao }
64145597088cSDongdong Hao
64155597088cSDongdong Hao if (le16_to_cpu(sas_dev_p0->flg) &
64165597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_FLG_ENC_LEVEL_VALID) {
64175597088cSDongdong Hao sas_dev->enc_level = sas_dev_p0->enc_level;
64185597088cSDongdong Hao memcpy(sas_dev->connector_name,
64195597088cSDongdong Hao sas_dev_p0->connector_name,
64205597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_CON_NAME_LEN);
64215597088cSDongdong Hao sas_dev->connector_name[
64225597088cSDongdong Hao LEAPRAID_SAS_DEV_P0_CON_NAME_LEN] = '\0';
64235597088cSDongdong Hao } else {
64245597088cSDongdong Hao sas_dev->enc_level = 0;
64255597088cSDongdong Hao sas_dev->connector_name[0] = '\0';
64265597088cSDongdong Hao }
64275597088cSDongdong Hao
64285597088cSDongdong Hao sas_dev->enc_hdl = enc_hdl;
64295597088cSDongdong Hao sas_dev->enc_lid = enc_lid;
64305597088cSDongdong Hao
64315597088cSDongdong Hao if (sas_dev->hdl == le16_to_cpu(sas_dev_p0->dev_hdl))
64325597088cSDongdong Hao goto unlock;
64335597088cSDongdong Hao
64345597088cSDongdong Hao dev_info(&adapter->pdev->dev,
64355597088cSDongdong Hao "hdl changed: 0x%04x -> 0x%04x\n",
64365597088cSDongdong Hao sas_dev->hdl, sas_dev_p0->dev_hdl);
64375597088cSDongdong Hao sas_dev->hdl = le16_to_cpu(sas_dev_p0->dev_hdl);
64385597088cSDongdong Hao if (starget_priv)
64395597088cSDongdong Hao starget_priv->hdl = le16_to_cpu(sas_dev_p0->dev_hdl);
64405597088cSDongdong Hao
64415597088cSDongdong Hao goto unlock;
64425597088cSDongdong Hao }
64435597088cSDongdong Hao unlock:
64445597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
64455597088cSDongdong Hao }
64465597088cSDongdong Hao
leapraid_search_resp_sas_dev(struct leapraid_adapter * adapter)64475597088cSDongdong Hao static void leapraid_search_resp_sas_dev(struct leapraid_adapter *adapter)
64485597088cSDongdong Hao {
64495597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
64505597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
64515597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_p0;
64525597088cSDongdong Hao u32 device_info;
64535597088cSDongdong Hao
64545597088cSDongdong Hao if (list_empty(&adapter->dev_topo.sas_dev_list))
64555597088cSDongdong Hao return;
64565597088cSDongdong Hao
64575597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
64585597088cSDongdong Hao for (cfgp2.handle = 0xFFFF;
64595597088cSDongdong Hao !leapraid_op_config_page(adapter, &sas_dev_p0,
64605597088cSDongdong Hao cfgp1, cfgp2, GET_SAS_DEVICE_PG0);
64615597088cSDongdong Hao cfgp2.handle = le16_to_cpu(sas_dev_p0.dev_hdl)) {
64625597088cSDongdong Hao device_info = le32_to_cpu(sas_dev_p0.dev_info);
64635597088cSDongdong Hao if (!(leapraid_is_end_dev(device_info)))
64645597088cSDongdong Hao continue;
64655597088cSDongdong Hao
64665597088cSDongdong Hao leapraid_mark_resp_sas_dev(adapter, &sas_dev_p0);
64675597088cSDongdong Hao }
64685597088cSDongdong Hao }
64695597088cSDongdong Hao
leapraid_mark_resp_raid_volume(struct leapraid_adapter * adapter,u64 wwid,u16 hdl)64705597088cSDongdong Hao static void leapraid_mark_resp_raid_volume(struct leapraid_adapter *adapter,
64715597088cSDongdong Hao u64 wwid, u16 hdl)
64725597088cSDongdong Hao {
64735597088cSDongdong Hao struct leapraid_raid_volume *raid_volume;
64745597088cSDongdong Hao struct leapraid_starget_priv *starget_priv = NULL;
64755597088cSDongdong Hao struct scsi_target *starget;
64765597088cSDongdong Hao unsigned long flags;
64775597088cSDongdong Hao u64 volume_wwid;
64785597088cSDongdong Hao u16 old_hdl;
64795597088cSDongdong Hao
64805597088cSDongdong Hao raid_volume = leapraid_raid_volume_find_by_wwid(adapter, wwid);
64815597088cSDongdong Hao if (!raid_volume)
64825597088cSDongdong Hao return;
64835597088cSDongdong Hao
64845597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
64855597088cSDongdong Hao if (!raid_volume->starget) {
64865597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock,
64875597088cSDongdong Hao flags);
64885597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
64895597088cSDongdong Hao return;
64905597088cSDongdong Hao }
64915597088cSDongdong Hao
64925597088cSDongdong Hao starget = raid_volume->starget;
64935597088cSDongdong Hao if (starget->hostdata) {
64945597088cSDongdong Hao starget_priv = starget->hostdata;
64955597088cSDongdong Hao starget_priv->deleted = 0;
64965597088cSDongdong Hao }
64975597088cSDongdong Hao
64985597088cSDongdong Hao raid_volume->resp = 1;
64995597088cSDongdong Hao volume_wwid = raid_volume->wwid;
65005597088cSDongdong Hao old_hdl = raid_volume->hdl;
65015597088cSDongdong Hao if (old_hdl != hdl) {
65025597088cSDongdong Hao raid_volume->hdl = hdl;
65035597088cSDongdong Hao if (starget_priv)
65045597088cSDongdong Hao starget_priv->hdl = hdl;
65055597088cSDongdong Hao }
65065597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
65075597088cSDongdong Hao
65085597088cSDongdong Hao starget_printk(KERN_INFO, starget,
65095597088cSDongdong Hao "raid volume: hdl=0x%04x, wwid=0x%016llx\n",
65105597088cSDongdong Hao hdl, (unsigned long long)volume_wwid);
65115597088cSDongdong Hao if (old_hdl != hdl)
65125597088cSDongdong Hao dev_info(&adapter->pdev->dev,
65135597088cSDongdong Hao "hdl changed: 0x%04x -> 0x%04x\n",
65145597088cSDongdong Hao old_hdl, hdl);
65155597088cSDongdong Hao
65165597088cSDongdong Hao leapraid_raid_volume_put(raid_volume);
65175597088cSDongdong Hao }
65185597088cSDongdong Hao
leapraid_search_resp_raid_volume(struct leapraid_adapter * adapter)65195597088cSDongdong Hao static void leapraid_search_resp_raid_volume(struct leapraid_adapter *adapter)
65205597088cSDongdong Hao {
65215597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
65225597088cSDongdong Hao union cfg_param_1 cfgp1_extra = {0};
65235597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
65245597088cSDongdong Hao union cfg_param_2 cfgp2_extra = {0};
65255597088cSDongdong Hao struct leapraid_raidvol_p1 raidvol_p1;
65265597088cSDongdong Hao struct leapraid_raidvol_p0 raidvol_p0;
65275597088cSDongdong Hao struct leapraid_raidpd_p0 raidpd_p0;
65285597088cSDongdong Hao unsigned long flags;
65295597088cSDongdong Hao u16 hdl;
65305597088cSDongdong Hao u8 phys_disk_num;
65315597088cSDongdong Hao bool is_empty;
65325597088cSDongdong Hao
65335597088cSDongdong Hao if (!adapter->adapter_attr.raid_support)
65345597088cSDongdong Hao return;
65355597088cSDongdong Hao
65365597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.raid_volume_lock, flags);
65375597088cSDongdong Hao is_empty = list_empty(&adapter->dev_topo.raid_volume_list);
65385597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.raid_volume_lock, flags);
65395597088cSDongdong Hao if (is_empty)
65405597088cSDongdong Hao return;
65415597088cSDongdong Hao
65425597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
65435597088cSDongdong Hao for (hdl = 0xFFFF, cfgp2.handle = hdl;
65445597088cSDongdong Hao !leapraid_op_config_page(adapter, &raidvol_p1, cfgp1, cfgp2,
65455597088cSDongdong Hao GET_RAID_VOLUME_PG1);
65465597088cSDongdong Hao cfgp2.handle = hdl) {
65475597088cSDongdong Hao hdl = le16_to_cpu(raidvol_p1.dev_hdl);
65485597088cSDongdong Hao cfgp1_extra.size = sizeof(struct leapraid_raidvol_p0);
65495597088cSDongdong Hao cfgp2_extra.handle = hdl;
65505597088cSDongdong Hao if (leapraid_op_config_page(adapter, &raidvol_p0, cfgp1_extra,
65515597088cSDongdong Hao cfgp2_extra, GET_RAID_VOLUME_PG0))
65525597088cSDongdong Hao continue;
65535597088cSDongdong Hao
65545597088cSDongdong Hao if (raidvol_p0.volume_state == LEAPRAID_VOL_STATE_OPTIMAL ||
65555597088cSDongdong Hao raidvol_p0.volume_state == LEAPRAID_VOL_STATE_ONLINE ||
65565597088cSDongdong Hao raidvol_p0.volume_state == LEAPRAID_VOL_STATE_DEGRADED)
65575597088cSDongdong Hao leapraid_mark_resp_raid_volume(
65585597088cSDongdong Hao adapter,
65595597088cSDongdong Hao le64_to_cpu(raidvol_p1.wwid),
65605597088cSDongdong Hao hdl);
65615597088cSDongdong Hao }
65625597088cSDongdong Hao
65635597088cSDongdong Hao memset(adapter->dev_topo.pd_hdls, 0, adapter->dev_topo.pd_hdls_sz);
65645597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
65655597088cSDongdong Hao for (phys_disk_num = 0xFF, cfgp2.form_specific = phys_disk_num;
65665597088cSDongdong Hao !leapraid_op_config_page(adapter, &raidpd_p0, cfgp1, cfgp2,
65675597088cSDongdong Hao GET_PHY_DISK_PG0);
65685597088cSDongdong Hao cfgp2.form_specific = phys_disk_num) {
65695597088cSDongdong Hao phys_disk_num = raidpd_p0.phys_disk_num;
65705597088cSDongdong Hao hdl = le16_to_cpu(raidpd_p0.dev_hdl);
65715597088cSDongdong Hao if (!hdl ||
65725597088cSDongdong Hao hdl > adapter->adapter_attr.features.max_dev_handle)
65735597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
65745597088cSDongdong Hao "%s: Invalid device handle\n", __func__);
65755597088cSDongdong Hao else
65765597088cSDongdong Hao set_bit(hdl, adapter->dev_topo.pd_hdls);
65775597088cSDongdong Hao }
65785597088cSDongdong Hao }
65795597088cSDongdong Hao
leapraid_mark_resp_exp(struct leapraid_adapter * adapter,struct leapraid_exp_p0 * exp_pg0)65805597088cSDongdong Hao static void leapraid_mark_resp_exp(struct leapraid_adapter *adapter,
65815597088cSDongdong Hao struct leapraid_exp_p0 *exp_pg0)
65825597088cSDongdong Hao {
65835597088cSDongdong Hao struct leapraid_enc_node *enc_node = NULL;
65845597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp;
65855597088cSDongdong Hao u16 enc_hdl = le16_to_cpu(exp_pg0->enc_hdl);
65865597088cSDongdong Hao u64 sas_address = le64_to_cpu(exp_pg0->sas_address);
65875597088cSDongdong Hao u16 hdl = le16_to_cpu(exp_pg0->dev_hdl);
65885597088cSDongdong Hao u8 port_id = exp_pg0->physical_port;
65895597088cSDongdong Hao struct leapraid_card_port *card_port = leapraid_get_port_by_id(adapter,
65905597088cSDongdong Hao port_id,
65915597088cSDongdong Hao false);
65925597088cSDongdong Hao unsigned long flags;
65935597088cSDongdong Hao unsigned long enc_flags = 0;
65945597088cSDongdong Hao u64 enc_lid = 0;
65955597088cSDongdong Hao int i;
65965597088cSDongdong Hao
65975597088cSDongdong Hao if (enc_hdl) {
65985597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.enc_lock, enc_flags);
65995597088cSDongdong Hao enc_node = leapraid_enc_find_by_hdl(adapter, enc_hdl);
66005597088cSDongdong Hao if (enc_node)
66015597088cSDongdong Hao enc_lid = le64_to_cpu(enc_node->pg0.enc_lid);
66025597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.enc_lock, enc_flags);
66035597088cSDongdong Hao }
66045597088cSDongdong Hao
66055597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
66065597088cSDongdong Hao list_for_each_entry(topo_node_exp, &adapter->dev_topo.exp_list, list) {
66075597088cSDongdong Hao if (topo_node_exp->sas_address != sas_address ||
66085597088cSDongdong Hao topo_node_exp->card_port != card_port)
66095597088cSDongdong Hao continue;
66105597088cSDongdong Hao
66115597088cSDongdong Hao topo_node_exp->resp = 1;
66125597088cSDongdong Hao topo_node_exp->enc_hdl = enc_hdl;
66135597088cSDongdong Hao topo_node_exp->enc_lid = enc_lid;
66145597088cSDongdong Hao if (topo_node_exp->hdl == hdl)
66155597088cSDongdong Hao goto unlock;
66165597088cSDongdong Hao
66175597088cSDongdong Hao dev_info(&adapter->pdev->dev,
66185597088cSDongdong Hao "hdl changed: 0x%04x -> 0x%04x\n",
66195597088cSDongdong Hao topo_node_exp->hdl, hdl);
66205597088cSDongdong Hao topo_node_exp->hdl = hdl;
66215597088cSDongdong Hao for (i = 0; i < topo_node_exp->phys_num; i++)
66225597088cSDongdong Hao topo_node_exp->card_phy[i].hdl = hdl;
66235597088cSDongdong Hao goto unlock;
66245597088cSDongdong Hao }
66255597088cSDongdong Hao unlock:
66265597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
66275597088cSDongdong Hao }
66285597088cSDongdong Hao
leapraid_search_resp_exp(struct leapraid_adapter * adapter)66295597088cSDongdong Hao static void leapraid_search_resp_exp(struct leapraid_adapter *adapter)
66305597088cSDongdong Hao {
66315597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
66325597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
66335597088cSDongdong Hao struct leapraid_exp_p0 exp_p0;
66345597088cSDongdong Hao u64 sas_address;
66355597088cSDongdong Hao u16 hdl;
66365597088cSDongdong Hao u8 port;
66375597088cSDongdong Hao
66385597088cSDongdong Hao if (list_empty(&adapter->dev_topo.exp_list))
66395597088cSDongdong Hao return;
66405597088cSDongdong Hao
66415597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_CFG_PGAD_GET_NEXT_LOOP;
66425597088cSDongdong Hao for (hdl = 0xFFFF, cfgp2.handle = hdl;
66435597088cSDongdong Hao !leapraid_op_config_page(adapter, &exp_p0, cfgp1, cfgp2,
66445597088cSDongdong Hao GET_SAS_EXPANDER_PG0);
66455597088cSDongdong Hao cfgp2.handle = hdl) {
66465597088cSDongdong Hao hdl = le16_to_cpu(exp_p0.dev_hdl);
66475597088cSDongdong Hao sas_address = le64_to_cpu(exp_p0.sas_address);
66485597088cSDongdong Hao port = exp_p0.physical_port;
66495597088cSDongdong Hao
66505597088cSDongdong Hao dev_dbg(&adapter->pdev->dev,
66515597088cSDongdong Hao "exp detected: hdl=0x%04x, sas=0x%016llx, port=%u",
66525597088cSDongdong Hao hdl, (unsigned long long)sas_address,
66535597088cSDongdong Hao adapter->adapter_attr.enable_mp ? port :
66545597088cSDongdong Hao LEAPRAID_DISABLE_MP_PORT_ID);
66555597088cSDongdong Hao leapraid_mark_resp_exp(adapter, &exp_p0);
66565597088cSDongdong Hao }
66575597088cSDongdong Hao }
66585597088cSDongdong Hao
leapraid_wait_cmds_done(struct leapraid_adapter * adapter)66595597088cSDongdong Hao void leapraid_wait_cmds_done(struct leapraid_adapter *adapter)
66605597088cSDongdong Hao {
66615597088cSDongdong Hao struct leapraid_io_req_tracker *io_req_tracker;
66625597088cSDongdong Hao unsigned long flags;
66635597088cSDongdong Hao u16 i;
66645597088cSDongdong Hao
66655597088cSDongdong Hao adapter->reset_desc.pending_io_cnt = 0;
66665597088cSDongdong Hao if (!leapraid_pci_active(adapter)) {
66675597088cSDongdong Hao dev_err(&adapter->pdev->dev,
66685597088cSDongdong Hao "%s %s: PCI error, device reset or unplugged!\n",
66695597088cSDongdong Hao adapter->adapter_attr.name, __func__);
66705597088cSDongdong Hao return;
66715597088cSDongdong Hao }
66725597088cSDongdong Hao
66735597088cSDongdong Hao if (leapraid_get_adapter_state(adapter) != LEAPRAID_DB_OPERATIONAL)
66745597088cSDongdong Hao return;
66755597088cSDongdong Hao
66765597088cSDongdong Hao spin_lock_irqsave(&adapter->dynamic_task_desc.task_lock, flags);
66775597088cSDongdong Hao for (i = 1; i <= adapter->shost->can_queue; i++) {
66785597088cSDongdong Hao io_req_tracker = leapraid_get_io_tracker_from_taskid(adapter,
66795597088cSDongdong Hao i);
66805597088cSDongdong Hao if (io_req_tracker && io_req_tracker->taskid != 0 &&
66815597088cSDongdong Hao io_req_tracker->scmd)
66825597088cSDongdong Hao adapter->reset_desc.pending_io_cnt++;
66835597088cSDongdong Hao }
66845597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dynamic_task_desc.task_lock, flags);
66855597088cSDongdong Hao
66865597088cSDongdong Hao if (!adapter->reset_desc.pending_io_cnt)
66875597088cSDongdong Hao return;
66885597088cSDongdong Hao
66895597088cSDongdong Hao wait_event_timeout(adapter->reset_desc.reset_wait_queue,
66905597088cSDongdong Hao adapter->reset_desc.pending_io_cnt == 0,
66915597088cSDongdong Hao LEAPRAID_IO_CMD_TIMEOUT * HZ);
66925597088cSDongdong Hao }
66935597088cSDongdong Hao
leapraid_hard_reset_handler(struct leapraid_adapter * adapter,enum reset_type type)66945597088cSDongdong Hao int leapraid_hard_reset_handler(struct leapraid_adapter *adapter,
66955597088cSDongdong Hao enum reset_type type)
66965597088cSDongdong Hao {
66975597088cSDongdong Hao unsigned long flags;
66985597088cSDongdong Hao bool wake = false;
66995597088cSDongdong Hao int rc;
67005597088cSDongdong Hao
67015597088cSDongdong Hao mutex_lock(&adapter->reset_desc.adapter_reset_mutex);
67025597088cSDongdong Hao
67035597088cSDongdong Hao if (adapter->access_ctrl.shost_recover_async) {
67045597088cSDongdong Hao rc = adapter->reset_desc.adapter_reset_results;
67055597088cSDongdong Hao dev_info(&adapter->pdev->dev,
67065597088cSDongdong Hao "Skip nested hard reset, async evt running, rc=%d\n",
67075597088cSDongdong Hao rc);
67085597088cSDongdong Hao mutex_unlock(&adapter->reset_desc.adapter_reset_mutex);
67095597088cSDongdong Hao return rc;
67105597088cSDongdong Hao }
67115597088cSDongdong Hao
67125597088cSDongdong Hao if (!leapraid_pci_active(adapter)) {
67135597088cSDongdong Hao if (leapraid_pci_removed(adapter)) {
67145597088cSDongdong Hao dev_info(&adapter->pdev->dev,
67155597088cSDongdong Hao "pci_dev removed, pause poll, clean cmds\n");
67165597088cSDongdong Hao leapraid_mq_polling_pause(adapter);
67175597088cSDongdong Hao leapraid_clean_active_scsi_cmds(adapter);
67185597088cSDongdong Hao leapraid_mq_polling_resume(adapter);
67195597088cSDongdong Hao }
67205597088cSDongdong Hao dev_err(&adapter->pdev->dev, "PCIe unavailable!\n");
67215597088cSDongdong Hao mutex_unlock(&adapter->reset_desc.adapter_reset_mutex);
67225597088cSDongdong Hao return -ENXIO;
67235597088cSDongdong Hao }
67245597088cSDongdong Hao
67255597088cSDongdong Hao dev_info(&adapter->pdev->dev, "Starting hard reset\n");
67265597088cSDongdong Hao
67275597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
67285597088cSDongdong Hao adapter->access_ctrl.shost_recovering = 1;
67295597088cSDongdong Hao adapter->access_ctrl.shost_recover_async = 1;
67305597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
67315597088cSDongdong Hao
67325597088cSDongdong Hao leapraid_wait_cmds_done(adapter);
67335597088cSDongdong Hao leapraid_mask_int(adapter);
67345597088cSDongdong Hao leapraid_mq_polling_pause(adapter);
67355597088cSDongdong Hao rc = leapraid_make_adapter_ready(adapter, type);
67365597088cSDongdong Hao if (rc) {
67375597088cSDongdong Hao dev_err(&adapter->pdev->dev,
67385597088cSDongdong Hao "Failed to make adapter ready, rc=%d\n", rc);
67395597088cSDongdong Hao goto out_cleanup;
67405597088cSDongdong Hao }
67415597088cSDongdong Hao
67425597088cSDongdong Hao rc = leapraid_fw_log_init(adapter);
67435597088cSDongdong Hao if (rc) {
67445597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Firmware log init failed\n");
67455597088cSDongdong Hao goto out_cleanup;
67465597088cSDongdong Hao }
67475597088cSDongdong Hao
67485597088cSDongdong Hao leapraid_clean_active_cmds(adapter);
67495597088cSDongdong Hao if (adapter->scan_dev_desc.driver_loading &&
67505597088cSDongdong Hao adapter->scan_dev_desc.scan_dev_failed) {
67515597088cSDongdong Hao dev_err(&adapter->pdev->dev,
67525597088cSDongdong Hao "Previous device scan failed or driver loading\n");
67535597088cSDongdong Hao adapter->access_ctrl.host_removing = 1;
67545597088cSDongdong Hao rc = -EFAULT;
67555597088cSDongdong Hao goto out_cleanup;
67565597088cSDongdong Hao }
67575597088cSDongdong Hao
67585597088cSDongdong Hao rc = leapraid_make_adapter_available(adapter);
67595597088cSDongdong Hao if (!rc) {
67605597088cSDongdong Hao dev_info(&adapter->pdev->dev,
67615597088cSDongdong Hao "Adapter is now available, rebuilding topology\n");
67625597088cSDongdong Hao if (adapter->adapter_attr.enable_mp) {
67635597088cSDongdong Hao leapraid_update_card_port_after_reset(adapter);
67645597088cSDongdong Hao leapraid_update_vphys_after_reset(adapter);
67655597088cSDongdong Hao }
67665597088cSDongdong Hao leapraid_mark_all_dev_deleted(adapter);
67675597088cSDongdong Hao leapraid_rebuild_enc_list_after_reset(adapter);
67685597088cSDongdong Hao leapraid_search_resp_sas_dev(adapter);
67695597088cSDongdong Hao leapraid_search_resp_raid_volume(adapter);
67705597088cSDongdong Hao leapraid_search_resp_exp(adapter);
67715597088cSDongdong Hao leapraid_hardreset_barrier(adapter);
67725597088cSDongdong Hao }
67735597088cSDongdong Hao out_cleanup:
67745597088cSDongdong Hao if (rc)
67755597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Hard reset failed\n");
67765597088cSDongdong Hao
67775597088cSDongdong Hao spin_lock_irqsave(&adapter->reset_desc.adapter_reset_lock, flags);
67785597088cSDongdong Hao adapter->reset_desc.adapter_reset_results = rc;
67795597088cSDongdong Hao adapter->access_ctrl.shost_recovering = 0;
67805597088cSDongdong Hao wake_up(&adapter->access_ctrl.recovery_waitq);
67815597088cSDongdong Hao if (rc) {
67825597088cSDongdong Hao adapter->access_ctrl.shost_recover_async = 0;
67835597088cSDongdong Hao wake = true;
67845597088cSDongdong Hao }
67855597088cSDongdong Hao spin_unlock_irqrestore(&adapter->reset_desc.adapter_reset_lock, flags);
67865597088cSDongdong Hao if (wake)
67875597088cSDongdong Hao wake_up(&adapter->access_ctrl.shost_recover_wq);
67885597088cSDongdong Hao
67895597088cSDongdong Hao adapter->reset_desc.reset_cnt++;
67905597088cSDongdong Hao mutex_unlock(&adapter->reset_desc.adapter_reset_mutex);
67915597088cSDongdong Hao
67925597088cSDongdong Hao if (rc)
67935597088cSDongdong Hao leapraid_clean_active_scsi_cmds(adapter);
67945597088cSDongdong Hao leapraid_mq_polling_resume(adapter);
67955597088cSDongdong Hao
67965597088cSDongdong Hao return rc;
67975597088cSDongdong Hao }
67985597088cSDongdong Hao
leapraid_get_adapter_features(struct leapraid_adapter * adapter)67995597088cSDongdong Hao static int leapraid_get_adapter_features(struct leapraid_adapter *adapter)
68005597088cSDongdong Hao {
68015597088cSDongdong Hao struct leapraid_adapter_features_req leap_mpi_req;
68025597088cSDongdong Hao struct leapraid_adapter_features_rep leap_mpi_rep;
68035597088cSDongdong Hao u8 fw_major, fw_minor, fw_build, fw_release;
68045597088cSDongdong Hao u32 req_sz;
68055597088cSDongdong Hao u32 rep_sz;
68065597088cSDongdong Hao u32 db;
68075597088cSDongdong Hao int r;
68085597088cSDongdong Hao
68095597088cSDongdong Hao db = leapraid_readl(&adapter->iomem_base->db);
68105597088cSDongdong Hao if (db & LEAPRAID_DB_USED ||
68115597088cSDongdong Hao (db & LEAPRAID_DB_MASK) == LEAPRAID_DB_FAULT) {
68125597088cSDongdong Hao dev_err(&adapter->pdev->dev,
68135597088cSDongdong Hao "%s: Doorbell used or fault\n", __func__);
68145597088cSDongdong Hao return -EFAULT;
68155597088cSDongdong Hao }
68165597088cSDongdong Hao
68175597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) != LEAPRAID_DB_READY &&
68185597088cSDongdong Hao (db & LEAPRAID_DB_MASK) != LEAPRAID_DB_OPERATIONAL &&
68195597088cSDongdong Hao !leapraid_wait_adapter_ready(adapter)) {
68205597088cSDongdong Hao dev_err(&adapter->pdev->dev,
68215597088cSDongdong Hao "%s: adapter not ready\n", __func__);
68225597088cSDongdong Hao return -EFAULT;
68235597088cSDongdong Hao }
68245597088cSDongdong Hao
68255597088cSDongdong Hao req_sz = sizeof(struct leapraid_adapter_features_req);
68265597088cSDongdong Hao rep_sz = sizeof(struct leapraid_adapter_features_rep);
68275597088cSDongdong Hao memset(&leap_mpi_req, 0, req_sz);
68285597088cSDongdong Hao memset(&leap_mpi_rep, 0, rep_sz);
68295597088cSDongdong Hao leap_mpi_req.func = LEAPRAID_FUNC_GET_ADAPTER_FEATURES;
68305597088cSDongdong Hao r = leapraid_handshake_func(adapter,
68315597088cSDongdong Hao req_sz,
68325597088cSDongdong Hao (u32 *)&leap_mpi_req,
68335597088cSDongdong Hao rep_sz,
68345597088cSDongdong Hao (u16 *)&leap_mpi_rep);
68355597088cSDongdong Hao if (r) {
68365597088cSDongdong Hao dev_err(&adapter->pdev->dev,
68375597088cSDongdong Hao "%s %s: Handshake failed, r=%d\n",
68385597088cSDongdong Hao adapter->adapter_attr.name, __func__, r);
68395597088cSDongdong Hao return r;
68405597088cSDongdong Hao }
68415597088cSDongdong Hao
68425597088cSDongdong Hao memset(&adapter->adapter_attr.features, 0,
68435597088cSDongdong Hao sizeof(struct leapraid_adapter_features));
68445597088cSDongdong Hao adapter->adapter_attr.features.req_slot =
68455597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.req_slot);
68465597088cSDongdong Hao adapter->adapter_attr.features.hp_slot =
68475597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.hp_slot);
68485597088cSDongdong Hao adapter->adapter_attr.features.adapter_caps =
68495597088cSDongdong Hao le32_to_cpu(leap_mpi_rep.adapter_caps);
68505597088cSDongdong Hao adapter->adapter_attr.features.max_msix_vectors =
68515597088cSDongdong Hao leap_mpi_rep.max_msix_vectors;
68525597088cSDongdong Hao adapter->adapter_attr.features.max_volumes =
68535597088cSDongdong Hao leap_mpi_rep.max_volumes;
68545597088cSDongdong Hao if (!adapter->adapter_attr.features.max_volumes)
68555597088cSDongdong Hao adapter->adapter_attr.features.max_volumes =
68565597088cSDongdong Hao LEAPRAID_MAX_VOLUMES_DEFAULT;
68575597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle =
68585597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.max_dev_hdl);
68595597088cSDongdong Hao if (!adapter->adapter_attr.features.max_dev_handle)
68605597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle =
68615597088cSDongdong Hao LEAPRAID_MAX_DEV_HANDLE_DEFAULT;
68625597088cSDongdong Hao adapter->adapter_attr.features.min_dev_handle =
68635597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.min_dev_hdl);
68645597088cSDongdong Hao if (adapter->adapter_attr.features.adapter_caps &
68655597088cSDongdong Hao LEAPRAID_ADAPTER_FEATURES_CAP_INTEGRATED_RAID)
68665597088cSDongdong Hao adapter->adapter_attr.raid_support = 1;
68675597088cSDongdong Hao adapter->adapter_attr.wideport_max_queue_depth =
68685597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.sas_wide_max_qdepth) ?
68695597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.sas_wide_max_qdepth) :
68705597088cSDongdong Hao LEAPRAID_SAS_QUEUE_DEPTH;
68715597088cSDongdong Hao adapter->adapter_attr.narrowport_max_queue_depth =
68725597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.sas_narrow_max_qdepth) ?
68735597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.sas_narrow_max_qdepth) :
68745597088cSDongdong Hao LEAPRAID_SAS_QUEUE_DEPTH;
68755597088cSDongdong Hao adapter->adapter_attr.sata_max_queue_depth =
68765597088cSDongdong Hao leap_mpi_rep.sata_max_qdepth ?
68775597088cSDongdong Hao leap_mpi_rep.sata_max_qdepth :
68785597088cSDongdong Hao LEAPRAID_SATA_QUEUE_DEPTH;
68795597088cSDongdong Hao adapter->adapter_attr.raid_volume_max_queue_depth =
68805597088cSDongdong Hao LEAPRAID_RAID_QUEUE_DEPTH;
68815597088cSDongdong Hao dev_info(&adapter->pdev->dev,
68825597088cSDongdong Hao "max: wp qd=%d, np qd=%d, SATA qd=%d, raid qd=%d\n",
68835597088cSDongdong Hao adapter->adapter_attr.wideport_max_queue_depth,
68845597088cSDongdong Hao adapter->adapter_attr.narrowport_max_queue_depth,
68855597088cSDongdong Hao adapter->adapter_attr.sata_max_queue_depth,
68865597088cSDongdong Hao adapter->adapter_attr.raid_volume_max_queue_depth);
68875597088cSDongdong Hao if (WARN_ON(!(adapter->adapter_attr.features.adapter_caps &
68885597088cSDongdong Hao LEAPRAID_ADAPTER_FEATURES_CAP_ATOMIC_REQ)))
68895597088cSDongdong Hao return -EFAULT;
68905597088cSDongdong Hao adapter->adapter_attr.features.fw_version =
68915597088cSDongdong Hao le32_to_cpu(leap_mpi_rep.fw_version);
68925597088cSDongdong Hao
68935597088cSDongdong Hao fw_major = (adapter->adapter_attr.features.fw_version >>
68945597088cSDongdong Hao LEAPRAID_VER_MAJOR_SHIFT) & LEAPRAID_VER_MASK;
68955597088cSDongdong Hao fw_minor = (adapter->adapter_attr.features.fw_version >>
68965597088cSDongdong Hao LEAPRAID_VER_MINOR_SHIFT) & LEAPRAID_VER_MASK;
68975597088cSDongdong Hao fw_build = (adapter->adapter_attr.features.fw_version >>
68985597088cSDongdong Hao LEAPRAID_VER_BUILD_SHIFT) & LEAPRAID_VER_MASK;
68995597088cSDongdong Hao fw_release =
69005597088cSDongdong Hao adapter->adapter_attr.features.fw_version & LEAPRAID_VER_MASK;
69015597088cSDongdong Hao
69025597088cSDongdong Hao dev_info(&adapter->pdev->dev,
69035597088cSDongdong Hao "Firmware version: %u.%u.%u.%u (0x%08x)\n",
69045597088cSDongdong Hao fw_major, fw_minor, fw_build, fw_release,
69055597088cSDongdong Hao adapter->adapter_attr.features.fw_version);
69065597088cSDongdong Hao
69075597088cSDongdong Hao adapter->adapter_attr.features.msg_ver =
69085597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.msg_ver);
69095597088cSDongdong Hao adapter->adapter_attr.features.product_id =
69105597088cSDongdong Hao le16_to_cpu(leap_mpi_rep.product_id);
69115597088cSDongdong Hao dev_info(&adapter->pdev->dev,
69125597088cSDongdong Hao "message version: 0x%x, product id 0x%x\n",
69135597088cSDongdong Hao adapter->adapter_attr.features.msg_ver,
69145597088cSDongdong Hao adapter->adapter_attr.features.product_id);
69155597088cSDongdong Hao
69165597088cSDongdong Hao if (adapter->adapter_attr.features.msg_ver < 0x1000) {
69175597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Device not supported\n");
69185597088cSDongdong Hao return -EFAULT;
69195597088cSDongdong Hao }
69205597088cSDongdong Hao adapter->shost->max_id = LEAPRAID_INVALID_INITIAL_VALUE;
69215597088cSDongdong Hao
69225597088cSDongdong Hao return 0;
69235597088cSDongdong Hao }
69245597088cSDongdong Hao
leapraid_disable_pcie(struct leapraid_adapter * adapter)69255597088cSDongdong Hao static inline void leapraid_disable_pcie(struct leapraid_adapter *adapter)
69265597088cSDongdong Hao {
69275597088cSDongdong Hao mutex_lock(&adapter->access_ctrl.pci_access_lock);
69285597088cSDongdong Hao if (adapter->iomem_base) {
69295597088cSDongdong Hao iounmap(adapter->iomem_base);
69305597088cSDongdong Hao adapter->iomem_base = NULL;
69315597088cSDongdong Hao }
69325597088cSDongdong Hao if (pci_is_enabled(adapter->pdev)) {
69335597088cSDongdong Hao pci_release_regions(adapter->pdev);
69345597088cSDongdong Hao pci_disable_device(adapter->pdev);
69355597088cSDongdong Hao }
69365597088cSDongdong Hao mutex_unlock(&adapter->access_ctrl.pci_access_lock);
69375597088cSDongdong Hao }
69385597088cSDongdong Hao
leapraid_enable_pcie(struct leapraid_adapter * adapter)69395597088cSDongdong Hao static int leapraid_enable_pcie(struct leapraid_adapter *adapter)
69405597088cSDongdong Hao {
69415597088cSDongdong Hao u64 dma_mask;
69425597088cSDongdong Hao int rc;
69435597088cSDongdong Hao
69445597088cSDongdong Hao rc = pci_enable_device(adapter->pdev);
69455597088cSDongdong Hao if (rc) {
69465597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Failed to enable PCI device\n");
69475597088cSDongdong Hao return rc;
69485597088cSDongdong Hao }
69495597088cSDongdong Hao
69505597088cSDongdong Hao rc = pci_request_regions(adapter->pdev, LEAPRAID_DRIVER_NAME);
69515597088cSDongdong Hao if (rc) {
69525597088cSDongdong Hao dev_err(&adapter->pdev->dev,
69535597088cSDongdong Hao "Failed to obtain PCI resources\n");
69545597088cSDongdong Hao return rc;
69555597088cSDongdong Hao }
69565597088cSDongdong Hao
69575597088cSDongdong Hao if (sizeof(dma_addr_t) > 4) {
69585597088cSDongdong Hao dma_mask = DMA_BIT_MASK(DMA_64_BITS);
69595597088cSDongdong Hao adapter->adapter_attr.use_32_dma_mask = 0;
69605597088cSDongdong Hao } else {
69615597088cSDongdong Hao dma_mask = DMA_BIT_MASK(DMA_32_BITS);
69625597088cSDongdong Hao adapter->adapter_attr.use_32_dma_mask = 1;
69635597088cSDongdong Hao }
69645597088cSDongdong Hao
69655597088cSDongdong Hao rc = dma_set_mask_and_coherent(&adapter->pdev->dev, dma_mask);
69665597088cSDongdong Hao if (rc) {
69675597088cSDongdong Hao dev_err(&adapter->pdev->dev,
69685597088cSDongdong Hao "Failed to set %lld DMA mask\n", dma_mask);
69695597088cSDongdong Hao return rc;
69705597088cSDongdong Hao }
69715597088cSDongdong Hao adapter->iomem_base = ioremap(pci_resource_start(adapter->pdev, 0),
69725597088cSDongdong Hao sizeof(struct leapraid_reg_base));
69735597088cSDongdong Hao if (!adapter->iomem_base) {
69745597088cSDongdong Hao dev_err(&adapter->pdev->dev,
69755597088cSDongdong Hao "Failed to map memory for controller registers\n");
69765597088cSDongdong Hao return -ENOMEM;
69775597088cSDongdong Hao }
69785597088cSDongdong Hao
69795597088cSDongdong Hao pci_set_master(adapter->pdev);
69805597088cSDongdong Hao
69815597088cSDongdong Hao return 0;
69825597088cSDongdong Hao }
69835597088cSDongdong Hao
leapraid_cpus_on_irq(struct leapraid_adapter * adapter)69845597088cSDongdong Hao static void leapraid_cpus_on_irq(struct leapraid_adapter *adapter)
69855597088cSDongdong Hao {
69865597088cSDongdong Hao struct leapraid_int_rq *int_rq;
69875597088cSDongdong Hao unsigned int i, base_group, this_group;
69885597088cSDongdong Hao unsigned int cpu, nr_cpus, total_msix, index;
69895597088cSDongdong Hao
69905597088cSDongdong Hao total_msix = adapter->notification_desc.iopoll_qdex;
69915597088cSDongdong Hao nr_cpus = num_online_cpus();
69925597088cSDongdong Hao
69935597088cSDongdong Hao if (!nr_cpus || !total_msix)
69945597088cSDongdong Hao return;
69955597088cSDongdong Hao base_group = nr_cpus / total_msix;
69965597088cSDongdong Hao
69975597088cSDongdong Hao cpu = cpumask_first(cpu_online_mask);
69985597088cSDongdong Hao for (index = 0; index < adapter->notification_desc.iopoll_qdex;
69995597088cSDongdong Hao index++) {
70005597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[index];
70015597088cSDongdong Hao
70025597088cSDongdong Hao if (cpu >= adapter->notification_desc.msix_cpu_map_sz)
70035597088cSDongdong Hao break;
70045597088cSDongdong Hao
70055597088cSDongdong Hao this_group = base_group +
70065597088cSDongdong Hao (index < (nr_cpus % total_msix) ? 1 : 0);
70075597088cSDongdong Hao
70085597088cSDongdong Hao for (i = 0 ; i < this_group ; i++) {
70095597088cSDongdong Hao if (cpu >= adapter->notification_desc.msix_cpu_map_sz)
70105597088cSDongdong Hao break;
70115597088cSDongdong Hao
70125597088cSDongdong Hao adapter->notification_desc.msix_cpu_map[cpu] =
70135597088cSDongdong Hao int_rq->rq.msix_idx;
70145597088cSDongdong Hao cpu = cpumask_next(cpu, cpu_online_mask);
70155597088cSDongdong Hao }
70165597088cSDongdong Hao }
70175597088cSDongdong Hao }
70185597088cSDongdong Hao
leapraid_map_msix_to_cpu(struct leapraid_adapter * adapter)70195597088cSDongdong Hao static void leapraid_map_msix_to_cpu(struct leapraid_adapter *adapter)
70205597088cSDongdong Hao {
70215597088cSDongdong Hao struct leapraid_int_rq *int_rq;
70225597088cSDongdong Hao const cpumask_t *affinity_mask;
70235597088cSDongdong Hao int cpu;
70245597088cSDongdong Hao u32 i;
70255597088cSDongdong Hao
70265597088cSDongdong Hao if (!adapter->adapter_attr.rq_cnt)
70275597088cSDongdong Hao return;
70285597088cSDongdong Hao
70295597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qdex; i++) {
70305597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[i];
70315597088cSDongdong Hao affinity_mask = pci_irq_get_affinity(adapter->pdev,
70325597088cSDongdong Hao int_rq->rq.msix_idx);
70335597088cSDongdong Hao if (!affinity_mask) {
70345597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
70355597088cSDongdong Hao "%s: IRQ affinity NULL, msix_idx=%d\n",
70365597088cSDongdong Hao __func__, int_rq->rq.msix_idx);
70375597088cSDongdong Hao goto out_apply_irq_affinity;
70385597088cSDongdong Hao }
70395597088cSDongdong Hao
70405597088cSDongdong Hao for_each_cpu_and(cpu, affinity_mask, cpu_online_mask) {
70415597088cSDongdong Hao if (cpu >= adapter->notification_desc.msix_cpu_map_sz)
70425597088cSDongdong Hao continue;
70435597088cSDongdong Hao
70445597088cSDongdong Hao adapter->notification_desc.msix_cpu_map[cpu] =
70455597088cSDongdong Hao int_rq->rq.msix_idx;
70465597088cSDongdong Hao }
70475597088cSDongdong Hao }
70485597088cSDongdong Hao return;
70495597088cSDongdong Hao out_apply_irq_affinity:
70505597088cSDongdong Hao leapraid_cpus_on_irq(adapter);
70515597088cSDongdong Hao }
70525597088cSDongdong Hao
leapraid_alloc_msix_cpu_map(struct leapraid_adapter * adapter)70535597088cSDongdong Hao static int leapraid_alloc_msix_cpu_map(struct leapraid_adapter *adapter)
70545597088cSDongdong Hao {
70555597088cSDongdong Hao adapter->notification_desc.msix_cpu_map_sz = nr_cpu_ids;
70565597088cSDongdong Hao adapter->notification_desc.msix_cpu_map =
70575597088cSDongdong Hao kzalloc(adapter->notification_desc.msix_cpu_map_sz,
70585597088cSDongdong Hao GFP_KERNEL);
70595597088cSDongdong Hao if (!adapter->notification_desc.msix_cpu_map)
70605597088cSDongdong Hao return -ENOMEM;
70615597088cSDongdong Hao
70625597088cSDongdong Hao return 0;
70635597088cSDongdong Hao }
70645597088cSDongdong Hao
leapraid_configure_reply_queue_affinity(struct leapraid_adapter * adapter)70655597088cSDongdong Hao static void leapraid_configure_reply_queue_affinity(
70665597088cSDongdong Hao struct leapraid_adapter *adapter)
70675597088cSDongdong Hao {
70685597088cSDongdong Hao if (!adapter || !adapter->notification_desc.msix_enable)
70695597088cSDongdong Hao return;
70705597088cSDongdong Hao
70715597088cSDongdong Hao leapraid_map_msix_to_cpu(adapter);
70725597088cSDongdong Hao }
70735597088cSDongdong Hao
leapraid_free_irq(struct leapraid_adapter * adapter)70745597088cSDongdong Hao static void leapraid_free_irq(struct leapraid_adapter *adapter)
70755597088cSDongdong Hao {
70765597088cSDongdong Hao struct leapraid_int_rq *int_rq;
70775597088cSDongdong Hao unsigned int i;
70785597088cSDongdong Hao int irq;
70795597088cSDongdong Hao
70805597088cSDongdong Hao for (i = 0; adapter->notification_desc.int_rqs &&
70815597088cSDongdong Hao i < adapter->notification_desc.int_rqs_allocated; i++) {
70825597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[i];
70835597088cSDongdong Hao if (!int_rq)
70845597088cSDongdong Hao continue;
70855597088cSDongdong Hao
70865597088cSDongdong Hao irq = pci_irq_vector(adapter->pdev, int_rq->rq.msix_idx);
70875597088cSDongdong Hao irq_set_affinity_hint(irq, NULL);
70885597088cSDongdong Hao free_irq(irq, &int_rq->rq);
70895597088cSDongdong Hao }
70905597088cSDongdong Hao adapter->notification_desc.int_rqs_allocated = 0;
70915597088cSDongdong Hao
70925597088cSDongdong Hao if (adapter->notification_desc.irq_vectors_allocated) {
70935597088cSDongdong Hao pci_free_irq_vectors(adapter->pdev);
70945597088cSDongdong Hao adapter->notification_desc.irq_vectors_allocated = 0;
70955597088cSDongdong Hao }
70965597088cSDongdong Hao
70975597088cSDongdong Hao adapter->notification_desc.msix_enable = 0;
70985597088cSDongdong Hao
70995597088cSDongdong Hao kfree(adapter->notification_desc.blk_mq_poll_rqs);
71005597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs = NULL;
71015597088cSDongdong Hao
71025597088cSDongdong Hao kfree(adapter->notification_desc.int_rqs);
71035597088cSDongdong Hao adapter->notification_desc.int_rqs = NULL;
71045597088cSDongdong Hao
71055597088cSDongdong Hao kfree(adapter->notification_desc.msix_cpu_map);
71065597088cSDongdong Hao adapter->notification_desc.msix_cpu_map = NULL;
71075597088cSDongdong Hao adapter->notification_desc.msix_cpu_map_sz = 0;
71085597088cSDongdong Hao adapter->notification_desc.iopoll_qdex = 0;
71095597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt = 0;
71105597088cSDongdong Hao }
71115597088cSDongdong Hao
leapraid_setup_irqs(struct leapraid_adapter * adapter)71125597088cSDongdong Hao static int leapraid_setup_irqs(struct leapraid_adapter *adapter)
71135597088cSDongdong Hao {
71145597088cSDongdong Hao int irq_mode = adapter->notification_desc.irq_mode;
71155597088cSDongdong Hao unsigned int i;
71165597088cSDongdong Hao int rc = 0;
71175597088cSDongdong Hao
71185597088cSDongdong Hao if (irq_mode == LEAPRAID_INTERRUPT_MODE_MSIX) {
71195597088cSDongdong Hao rc = pci_alloc_irq_vectors_affinity(
71205597088cSDongdong Hao adapter->pdev,
71215597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
71225597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
71235597088cSDongdong Hao PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, NULL);
71245597088cSDongdong Hao if (rc < 0) {
71255597088cSDongdong Hao dev_err(&adapter->pdev->dev,
71265597088cSDongdong Hao "%d MSI/MSIX vectors allocated failed!\n",
71275597088cSDongdong Hao adapter->notification_desc.iopoll_qdex);
71285597088cSDongdong Hao return rc;
71295597088cSDongdong Hao }
71305597088cSDongdong Hao
71315597088cSDongdong Hao adapter->notification_desc.irq_vectors_allocated = 1;
71325597088cSDongdong Hao }
71335597088cSDongdong Hao
71345597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qdex; i++) {
71355597088cSDongdong Hao adapter->notification_desc.int_rqs[i].rq.adapter = adapter;
71365597088cSDongdong Hao adapter->notification_desc.int_rqs[i].rq.msix_idx = i;
71375597088cSDongdong Hao atomic_set(&adapter->notification_desc.int_rqs[i].rq.busy, 0);
71385597088cSDongdong Hao if (irq_mode == LEAPRAID_INTERRUPT_MODE_MSIX)
71395597088cSDongdong Hao snprintf(adapter->notification_desc.int_rqs[i].rq.name,
71405597088cSDongdong Hao LEAPRAID_NAME_LENGTH, "%s%u-MSIx%u",
71415597088cSDongdong Hao LEAPRAID_DRIVER_NAME,
71425597088cSDongdong Hao adapter->adapter_attr.id, i);
71435597088cSDongdong Hao else if (irq_mode == LEAPRAID_INTERRUPT_MODE_MSI)
71445597088cSDongdong Hao snprintf(adapter->notification_desc.int_rqs[i].rq.name,
71455597088cSDongdong Hao LEAPRAID_NAME_LENGTH, "%s%u-MSI%u",
71465597088cSDongdong Hao LEAPRAID_DRIVER_NAME,
71475597088cSDongdong Hao adapter->adapter_attr.id, i);
71485597088cSDongdong Hao
71495597088cSDongdong Hao rc = request_irq(pci_irq_vector(adapter->pdev, i),
71505597088cSDongdong Hao leapraid_irq_handler,
71515597088cSDongdong Hao IRQF_SHARED,
71525597088cSDongdong Hao adapter->notification_desc.int_rqs[i].rq.name,
71535597088cSDongdong Hao &adapter->notification_desc.int_rqs[i].rq);
71545597088cSDongdong Hao if (rc) {
71555597088cSDongdong Hao dev_err(&adapter->pdev->dev,
71565597088cSDongdong Hao "MSI/MSIx: request_irq %s failed!\n",
71575597088cSDongdong Hao adapter->notification_desc.int_rqs[i].rq.name);
71585597088cSDongdong Hao return rc;
71595597088cSDongdong Hao }
71605597088cSDongdong Hao adapter->notification_desc.int_rqs_allocated++;
71615597088cSDongdong Hao }
71625597088cSDongdong Hao
71635597088cSDongdong Hao return 0;
71645597088cSDongdong Hao }
71655597088cSDongdong Hao
leapraid_setup_legacy_int(struct leapraid_adapter * adapter)71665597088cSDongdong Hao static int leapraid_setup_legacy_int(struct leapraid_adapter *adapter)
71675597088cSDongdong Hao {
71685597088cSDongdong Hao int rc;
71695597088cSDongdong Hao
71705597088cSDongdong Hao adapter->notification_desc.int_rqs[0].rq.adapter = adapter;
71715597088cSDongdong Hao adapter->notification_desc.int_rqs[0].rq.msix_idx = 0;
71725597088cSDongdong Hao atomic_set(&adapter->notification_desc.int_rqs[0].rq.busy, 0);
71735597088cSDongdong Hao snprintf(adapter->notification_desc.int_rqs[0].rq.name,
71745597088cSDongdong Hao LEAPRAID_NAME_LENGTH, "%s%d-LegacyInt",
71755597088cSDongdong Hao LEAPRAID_DRIVER_NAME, adapter->adapter_attr.id);
71765597088cSDongdong Hao
71775597088cSDongdong Hao rc = pci_alloc_irq_vectors_affinity(
71785597088cSDongdong Hao adapter->pdev,
71795597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
71805597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
71815597088cSDongdong Hao PCI_IRQ_INTX | PCI_IRQ_AFFINITY,
71825597088cSDongdong Hao NULL);
71835597088cSDongdong Hao if (rc < 0) {
71845597088cSDongdong Hao dev_err(&adapter->pdev->dev,
71855597088cSDongdong Hao "Legacy irq allocated failed!\n");
71865597088cSDongdong Hao return rc;
71875597088cSDongdong Hao }
71885597088cSDongdong Hao
71895597088cSDongdong Hao adapter->notification_desc.irq_vectors_allocated = 1;
71905597088cSDongdong Hao adapter->notification_desc.irq_mode = LEAPRAID_INTERRUPT_MODE_LEGACY;
71915597088cSDongdong Hao rc = request_irq(pci_irq_vector(adapter->pdev, 0),
71925597088cSDongdong Hao leapraid_irq_handler,
71935597088cSDongdong Hao IRQF_SHARED,
71945597088cSDongdong Hao adapter->notification_desc.int_rqs[0].rq.name,
71955597088cSDongdong Hao &adapter->notification_desc.int_rqs[0].rq);
71965597088cSDongdong Hao if (rc) {
71975597088cSDongdong Hao irq_set_affinity_hint(pci_irq_vector(adapter->pdev, 0), NULL);
71985597088cSDongdong Hao pci_free_irq_vectors(adapter->pdev);
71995597088cSDongdong Hao adapter->notification_desc.irq_vectors_allocated = 0;
72005597088cSDongdong Hao dev_err(&adapter->pdev->dev,
72015597088cSDongdong Hao "Legacy Int: request_irq %s failed!\n",
72025597088cSDongdong Hao adapter->notification_desc.int_rqs[0].rq.name);
72035597088cSDongdong Hao return -EBUSY;
72045597088cSDongdong Hao }
72055597088cSDongdong Hao adapter->notification_desc.int_rqs_allocated = 1;
72065597088cSDongdong Hao return rc;
72075597088cSDongdong Hao }
72085597088cSDongdong Hao
leapraid_set_legacy_int(struct leapraid_adapter * adapter)72095597088cSDongdong Hao static int leapraid_set_legacy_int(struct leapraid_adapter *adapter)
72105597088cSDongdong Hao {
72115597088cSDongdong Hao int rc;
72125597088cSDongdong Hao
72135597088cSDongdong Hao rc = leapraid_alloc_msix_cpu_map(adapter);
72145597088cSDongdong Hao if (rc)
72155597088cSDongdong Hao return rc;
72165597088cSDongdong Hao
72175597088cSDongdong Hao adapter->adapter_attr.rq_cnt = 1;
72185597088cSDongdong Hao adapter->notification_desc.iopoll_qdex =
72195597088cSDongdong Hao adapter->adapter_attr.rq_cnt;
72205597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt = 0;
72215597088cSDongdong Hao dev_info(&adapter->pdev->dev,
72225597088cSDongdong Hao "Legacy Intr: req queue cnt=%d intr=%d/poll=%d rep queues!\n",
72235597088cSDongdong Hao adapter->adapter_attr.rq_cnt,
72245597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
72255597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt);
72265597088cSDongdong Hao adapter->notification_desc.int_rqs =
72275597088cSDongdong Hao kcalloc(adapter->notification_desc.iopoll_qdex,
72285597088cSDongdong Hao sizeof(struct leapraid_int_rq), GFP_KERNEL);
72295597088cSDongdong Hao if (!adapter->notification_desc.int_rqs)
72305597088cSDongdong Hao return -ENOMEM;
72315597088cSDongdong Hao
72325597088cSDongdong Hao return leapraid_setup_legacy_int(adapter);
72335597088cSDongdong Hao }
72345597088cSDongdong Hao
leapraid_set_msix(struct leapraid_adapter * adapter)72355597088cSDongdong Hao static int leapraid_set_msix(struct leapraid_adapter *adapter)
72365597088cSDongdong Hao {
72375597088cSDongdong Hao int iopoll_qcnt = 0;
72385597088cSDongdong Hao unsigned int i;
72395597088cSDongdong Hao int rc, msix_cnt;
72405597088cSDongdong Hao
72415597088cSDongdong Hao msix_cnt = pci_msix_vec_count(adapter->pdev);
72425597088cSDongdong Hao if (msix_cnt <= 0 ||
72435597088cSDongdong Hao adapter->adapter_attr.features.max_msix_vectors == 0) {
72445597088cSDongdong Hao dev_info(&adapter->pdev->dev, "MSIX unsupported!\n");
72455597088cSDongdong Hao return -EOPNOTSUPP;
72465597088cSDongdong Hao }
72475597088cSDongdong Hao
72485597088cSDongdong Hao msix_cnt = min_t(int, msix_cnt,
72495597088cSDongdong Hao adapter->adapter_attr.features.max_msix_vectors);
72505597088cSDongdong Hao
72515597088cSDongdong Hao if (reset_devices)
72525597088cSDongdong Hao adapter->adapter_attr.rq_cnt = 1;
72535597088cSDongdong Hao else
72545597088cSDongdong Hao adapter->adapter_attr.rq_cnt = min_t(int,
72555597088cSDongdong Hao num_online_cpus(),
72565597088cSDongdong Hao msix_cnt);
72575597088cSDongdong Hao
72585597088cSDongdong Hao if (max_msix_vectors > 0)
72595597088cSDongdong Hao adapter->adapter_attr.rq_cnt = min_t(
72605597088cSDongdong Hao int, max_msix_vectors, adapter->adapter_attr.rq_cnt);
72615597088cSDongdong Hao
72625597088cSDongdong Hao if (adapter->adapter_attr.rq_cnt <= 1)
72635597088cSDongdong Hao adapter->shost->host_tagset = 0;
72645597088cSDongdong Hao if (adapter->shost->host_tagset) {
72655597088cSDongdong Hao iopoll_qcnt = poll_queues;
72665597088cSDongdong Hao if (iopoll_qcnt >= adapter->adapter_attr.rq_cnt)
72675597088cSDongdong Hao iopoll_qcnt = 0;
72685597088cSDongdong Hao }
72695597088cSDongdong Hao if (iopoll_qcnt) {
72705597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs =
72715597088cSDongdong Hao kcalloc(iopoll_qcnt,
72725597088cSDongdong Hao sizeof(struct leapraid_blk_mq_poll_rq),
72735597088cSDongdong Hao GFP_KERNEL);
72745597088cSDongdong Hao if (!adapter->notification_desc.blk_mq_poll_rqs)
72755597088cSDongdong Hao return -ENOMEM;
72765597088cSDongdong Hao adapter->adapter_attr.rq_cnt =
72775597088cSDongdong Hao min(adapter->adapter_attr.rq_cnt + iopoll_qcnt,
72785597088cSDongdong Hao msix_cnt);
72795597088cSDongdong Hao }
72805597088cSDongdong Hao
72815597088cSDongdong Hao adapter->notification_desc.iopoll_qdex =
72825597088cSDongdong Hao adapter->adapter_attr.rq_cnt - iopoll_qcnt;
72835597088cSDongdong Hao
72845597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt = iopoll_qcnt;
72855597088cSDongdong Hao dev_info(&adapter->pdev->dev,
72865597088cSDongdong Hao "MSIx: req queue cnt=%d, intr=%d/poll=%d rep queues!\n",
72875597088cSDongdong Hao adapter->adapter_attr.rq_cnt,
72885597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
72895597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt);
72905597088cSDongdong Hao
72915597088cSDongdong Hao adapter->notification_desc.int_rqs =
72925597088cSDongdong Hao kcalloc(adapter->notification_desc.iopoll_qdex,
72935597088cSDongdong Hao sizeof(struct leapraid_int_rq), GFP_KERNEL);
72945597088cSDongdong Hao if (!adapter->notification_desc.int_rqs)
72955597088cSDongdong Hao return -ENOMEM;
72965597088cSDongdong Hao
72975597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qcnt; i++) {
72985597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs[i].rq.adapter =
72995597088cSDongdong Hao adapter;
73005597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs[i].rq.msix_idx =
73015597088cSDongdong Hao i + adapter->notification_desc.iopoll_qdex;
73025597088cSDongdong Hao atomic_set(
73035597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i].rq.busy,
73045597088cSDongdong Hao 0);
73055597088cSDongdong Hao snprintf(adapter->notification_desc.blk_mq_poll_rqs[i].rq.name,
73065597088cSDongdong Hao LEAPRAID_NAME_LENGTH,
73075597088cSDongdong Hao "%s%u-MQ-Poll%u", LEAPRAID_DRIVER_NAME,
73085597088cSDongdong Hao adapter->adapter_attr.id, i);
73095597088cSDongdong Hao atomic_set(&adapter->notification_desc.blk_mq_poll_rqs[i].busy,
73105597088cSDongdong Hao 0);
73115597088cSDongdong Hao atomic_set(&adapter->notification_desc.blk_mq_poll_rqs[i].pause,
73125597088cSDongdong Hao 0);
73135597088cSDongdong Hao }
73145597088cSDongdong Hao
73155597088cSDongdong Hao rc = leapraid_alloc_msix_cpu_map(adapter);
73165597088cSDongdong Hao if (rc)
73175597088cSDongdong Hao return rc;
73185597088cSDongdong Hao
73195597088cSDongdong Hao adapter->notification_desc.irq_mode = LEAPRAID_INTERRUPT_MODE_MSIX;
73205597088cSDongdong Hao adapter->notification_desc.msix_enable = 1;
73215597088cSDongdong Hao rc = leapraid_setup_irqs(adapter);
73225597088cSDongdong Hao if (rc) {
73235597088cSDongdong Hao leapraid_free_irq(adapter);
73245597088cSDongdong Hao adapter->notification_desc.msix_enable = 0;
73255597088cSDongdong Hao return rc;
73265597088cSDongdong Hao }
73275597088cSDongdong Hao
73285597088cSDongdong Hao return 0;
73295597088cSDongdong Hao }
73305597088cSDongdong Hao
leapraid_set_msi(struct leapraid_adapter * adapter)73315597088cSDongdong Hao static int leapraid_set_msi(struct leapraid_adapter *adapter)
73325597088cSDongdong Hao {
73335597088cSDongdong Hao int iopoll_qcnt = 0;
73345597088cSDongdong Hao unsigned int i;
73355597088cSDongdong Hao int rc, msi_cnt;
73365597088cSDongdong Hao
73375597088cSDongdong Hao msi_cnt = pci_msi_vec_count(adapter->pdev);
73385597088cSDongdong Hao if (msi_cnt <= 0 ||
73395597088cSDongdong Hao adapter->adapter_attr.features.max_msix_vectors == 0) {
73405597088cSDongdong Hao dev_info(&adapter->pdev->dev, "MSI unsupported!\n");
73415597088cSDongdong Hao return -EOPNOTSUPP;
73425597088cSDongdong Hao }
73435597088cSDongdong Hao
73445597088cSDongdong Hao msi_cnt = min_t(int, msi_cnt,
73455597088cSDongdong Hao adapter->adapter_attr.features.max_msix_vectors);
73465597088cSDongdong Hao
73475597088cSDongdong Hao if (reset_devices)
73485597088cSDongdong Hao adapter->adapter_attr.rq_cnt = 1;
73495597088cSDongdong Hao else
73505597088cSDongdong Hao adapter->adapter_attr.rq_cnt = min_t(int,
73515597088cSDongdong Hao num_online_cpus(),
73525597088cSDongdong Hao msi_cnt);
73535597088cSDongdong Hao
73545597088cSDongdong Hao if (max_msix_vectors > 0)
73555597088cSDongdong Hao adapter->adapter_attr.rq_cnt = min_t(
73565597088cSDongdong Hao int, max_msix_vectors, adapter->adapter_attr.rq_cnt);
73575597088cSDongdong Hao
73585597088cSDongdong Hao if (adapter->adapter_attr.rq_cnt <= 1)
73595597088cSDongdong Hao adapter->shost->host_tagset = 0;
73605597088cSDongdong Hao if (adapter->shost->host_tagset) {
73615597088cSDongdong Hao iopoll_qcnt = poll_queues;
73625597088cSDongdong Hao if (iopoll_qcnt >= adapter->adapter_attr.rq_cnt)
73635597088cSDongdong Hao iopoll_qcnt = 0;
73645597088cSDongdong Hao }
73655597088cSDongdong Hao
73665597088cSDongdong Hao if (iopoll_qcnt) {
73675597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs =
73685597088cSDongdong Hao kcalloc(iopoll_qcnt,
73695597088cSDongdong Hao sizeof(struct leapraid_blk_mq_poll_rq),
73705597088cSDongdong Hao GFP_KERNEL);
73715597088cSDongdong Hao if (!adapter->notification_desc.blk_mq_poll_rqs)
73725597088cSDongdong Hao return -ENOMEM;
73735597088cSDongdong Hao
73745597088cSDongdong Hao adapter->adapter_attr.rq_cnt =
73755597088cSDongdong Hao min(adapter->adapter_attr.rq_cnt + iopoll_qcnt,
73765597088cSDongdong Hao msi_cnt);
73775597088cSDongdong Hao }
73785597088cSDongdong Hao
73795597088cSDongdong Hao adapter->notification_desc.iopoll_qdex =
73805597088cSDongdong Hao adapter->adapter_attr.rq_cnt - iopoll_qcnt;
73815597088cSDongdong Hao rc = pci_alloc_irq_vectors_affinity(
73825597088cSDongdong Hao adapter->pdev,
73835597088cSDongdong Hao 1,
73845597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
73855597088cSDongdong Hao PCI_IRQ_MSI | PCI_IRQ_AFFINITY, NULL);
73865597088cSDongdong Hao if (rc < 0) {
73875597088cSDongdong Hao dev_err(&adapter->pdev->dev,
73885597088cSDongdong Hao "%d MSI vectors allocated failed!\n",
73895597088cSDongdong Hao adapter->notification_desc.iopoll_qdex);
73905597088cSDongdong Hao leapraid_free_irq(adapter);
73915597088cSDongdong Hao return rc;
73925597088cSDongdong Hao }
73935597088cSDongdong Hao adapter->notification_desc.irq_vectors_allocated = 1;
73945597088cSDongdong Hao if (rc != adapter->notification_desc.iopoll_qdex) {
73955597088cSDongdong Hao adapter->notification_desc.iopoll_qdex = rc;
73965597088cSDongdong Hao adapter->adapter_attr.rq_cnt =
73975597088cSDongdong Hao adapter->notification_desc.iopoll_qdex + iopoll_qcnt;
73985597088cSDongdong Hao }
73995597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt = iopoll_qcnt;
74005597088cSDongdong Hao dev_info(&adapter->pdev->dev,
74015597088cSDongdong Hao "MSI: req queue cnt=%d, intr=%d/poll=%d rep queues!\n",
74025597088cSDongdong Hao adapter->adapter_attr.rq_cnt,
74035597088cSDongdong Hao adapter->notification_desc.iopoll_qdex,
74045597088cSDongdong Hao adapter->notification_desc.iopoll_qcnt);
74055597088cSDongdong Hao
74065597088cSDongdong Hao adapter->notification_desc.int_rqs =
74075597088cSDongdong Hao kcalloc(adapter->notification_desc.iopoll_qdex,
74085597088cSDongdong Hao sizeof(struct leapraid_int_rq),
74095597088cSDongdong Hao GFP_KERNEL);
74105597088cSDongdong Hao if (!adapter->notification_desc.int_rqs)
74115597088cSDongdong Hao return -ENOMEM;
74125597088cSDongdong Hao
74135597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qcnt; i++) {
74145597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs[i].rq.adapter =
74155597088cSDongdong Hao adapter;
74165597088cSDongdong Hao adapter->notification_desc.blk_mq_poll_rqs[i].rq.msix_idx =
74175597088cSDongdong Hao i + adapter->notification_desc.iopoll_qdex;
74185597088cSDongdong Hao atomic_set(
74195597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i].rq.busy,
74205597088cSDongdong Hao 0);
74215597088cSDongdong Hao snprintf(adapter->notification_desc.blk_mq_poll_rqs[i].rq.name,
74225597088cSDongdong Hao LEAPRAID_NAME_LENGTH,
74235597088cSDongdong Hao "%s%u-MQ-Poll%u", LEAPRAID_DRIVER_NAME,
74245597088cSDongdong Hao adapter->adapter_attr.id, i);
74255597088cSDongdong Hao atomic_set(
74265597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i].busy,
74275597088cSDongdong Hao 0);
74285597088cSDongdong Hao atomic_set(
74295597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i].pause,
74305597088cSDongdong Hao 0);
74315597088cSDongdong Hao }
74325597088cSDongdong Hao
74335597088cSDongdong Hao rc = leapraid_alloc_msix_cpu_map(adapter);
74345597088cSDongdong Hao if (rc)
74355597088cSDongdong Hao return rc;
74365597088cSDongdong Hao
74375597088cSDongdong Hao adapter->notification_desc.irq_mode = LEAPRAID_INTERRUPT_MODE_MSI;
74385597088cSDongdong Hao adapter->notification_desc.msix_enable = 1;
74395597088cSDongdong Hao rc = leapraid_setup_irqs(adapter);
74405597088cSDongdong Hao if (rc) {
74415597088cSDongdong Hao leapraid_free_irq(adapter);
74425597088cSDongdong Hao adapter->notification_desc.msix_enable = 0;
74435597088cSDongdong Hao return rc;
74445597088cSDongdong Hao }
74455597088cSDongdong Hao
74465597088cSDongdong Hao return 0;
74475597088cSDongdong Hao }
74485597088cSDongdong Hao
leapraid_set_notification_auto(struct leapraid_adapter * adapter)74495597088cSDongdong Hao static int leapraid_set_notification_auto(struct leapraid_adapter *adapter)
74505597088cSDongdong Hao {
74515597088cSDongdong Hao int rc;
74525597088cSDongdong Hao
74535597088cSDongdong Hao rc = leapraid_set_msix(adapter);
74545597088cSDongdong Hao if (!rc)
74555597088cSDongdong Hao return 0;
74565597088cSDongdong Hao
74575597088cSDongdong Hao leapraid_free_irq(adapter);
74585597088cSDongdong Hao dev_info(&adapter->pdev->dev,
74595597088cSDongdong Hao "MSI-X setup failed (%d), trying MSI\n", rc);
74605597088cSDongdong Hao
74615597088cSDongdong Hao rc = leapraid_set_msi(adapter);
74625597088cSDongdong Hao if (!rc)
74635597088cSDongdong Hao return 0;
74645597088cSDongdong Hao
74655597088cSDongdong Hao leapraid_free_irq(adapter);
74665597088cSDongdong Hao dev_info(&adapter->pdev->dev,
74675597088cSDongdong Hao "MSI setup failed (%d), back to legacy INTx\n", rc);
74685597088cSDongdong Hao
74695597088cSDongdong Hao rc = leapraid_set_legacy_int(adapter);
74705597088cSDongdong Hao if (rc)
74715597088cSDongdong Hao dev_err(&adapter->pdev->dev,
74725597088cSDongdong Hao "%s: Enable legacy irq failed!\n", __func__);
74735597088cSDongdong Hao
74745597088cSDongdong Hao return rc;
74755597088cSDongdong Hao }
74765597088cSDongdong Hao
leapraid_set_pcie_and_notification(struct leapraid_adapter * adapter)74775597088cSDongdong Hao int leapraid_set_pcie_and_notification(struct leapraid_adapter *adapter)
74785597088cSDongdong Hao {
74795597088cSDongdong Hao int rc;
74805597088cSDongdong Hao
74815597088cSDongdong Hao rc = leapraid_enable_pcie(adapter);
74825597088cSDongdong Hao if (rc)
74835597088cSDongdong Hao goto out_fail;
74845597088cSDongdong Hao
74855597088cSDongdong Hao leapraid_mask_int(adapter);
74865597088cSDongdong Hao
74875597088cSDongdong Hao rc = leapraid_make_adapter_ready(adapter, PART_RESET);
74885597088cSDongdong Hao if (rc) {
74895597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Make adapter ready failure\n");
74905597088cSDongdong Hao goto out_fail;
74915597088cSDongdong Hao }
74925597088cSDongdong Hao
74935597088cSDongdong Hao rc = leapraid_get_adapter_features(adapter);
74945597088cSDongdong Hao if (rc) {
74955597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Get adapter feature failure\n");
74965597088cSDongdong Hao goto out_fail;
74975597088cSDongdong Hao }
74985597088cSDongdong Hao
74995597088cSDongdong Hao rc = leapraid_set_notification_auto(adapter);
75005597088cSDongdong Hao if (rc)
75015597088cSDongdong Hao goto out_fail;
75025597088cSDongdong Hao
75035597088cSDongdong Hao pci_save_state(adapter->pdev);
75045597088cSDongdong Hao
75055597088cSDongdong Hao return 0;
75065597088cSDongdong Hao
75075597088cSDongdong Hao out_fail:
75085597088cSDongdong Hao leapraid_free_irq(adapter);
75095597088cSDongdong Hao leapraid_disable_pcie(adapter);
75105597088cSDongdong Hao return rc;
75115597088cSDongdong Hao }
75125597088cSDongdong Hao
leapraid_disable_controller(struct leapraid_adapter * adapter)75135597088cSDongdong Hao void leapraid_disable_controller(struct leapraid_adapter *adapter)
75145597088cSDongdong Hao {
75155597088cSDongdong Hao if (!adapter->iomem_base)
75165597088cSDongdong Hao return;
75175597088cSDongdong Hao
75185597088cSDongdong Hao leapraid_mask_int(adapter);
75195597088cSDongdong Hao
75205597088cSDongdong Hao adapter->access_ctrl.shost_recovering = 1;
75215597088cSDongdong Hao leapraid_make_adapter_ready(adapter, PART_RESET);
75225597088cSDongdong Hao adapter->access_ctrl.shost_recovering = 0;
75235597088cSDongdong Hao wake_up(&adapter->access_ctrl.recovery_waitq);
75245597088cSDongdong Hao
75255597088cSDongdong Hao leapraid_free_irq(adapter);
75265597088cSDongdong Hao leapraid_disable_pcie(adapter);
75275597088cSDongdong Hao }
75285597088cSDongdong Hao
leapraid_adapter_unit_reset(struct leapraid_adapter * adapter)75295597088cSDongdong Hao static int leapraid_adapter_unit_reset(struct leapraid_adapter *adapter)
75305597088cSDongdong Hao {
75315597088cSDongdong Hao int rc = 0;
75325597088cSDongdong Hao
75335597088cSDongdong Hao writel(LEAPRAID_FUNC_ADAPTER_UNIT_RESET << LEAPRAID_DB_FUNC_SHIFT,
75345597088cSDongdong Hao &adapter->iomem_base->db);
75355597088cSDongdong Hao if (leapraid_db_wait_ack_and_clear_int(adapter))
75365597088cSDongdong Hao rc = -EFAULT;
75375597088cSDongdong Hao
75385597088cSDongdong Hao if (!leapraid_wait_adapter_ready(adapter)) {
75395597088cSDongdong Hao dev_err(&adapter->pdev->dev, "unit reset failed\n");
75405597088cSDongdong Hao return -EFAULT;
75415597088cSDongdong Hao }
75425597088cSDongdong Hao
75435597088cSDongdong Hao return rc;
75445597088cSDongdong Hao }
75455597088cSDongdong Hao
leapraid_make_adapter_ready(struct leapraid_adapter * adapter,enum reset_type type)75465597088cSDongdong Hao static int leapraid_make_adapter_ready(struct leapraid_adapter *adapter,
75475597088cSDongdong Hao enum reset_type type)
75485597088cSDongdong Hao {
75495597088cSDongdong Hao u32 db;
75505597088cSDongdong Hao int count;
75515597088cSDongdong Hao
75525597088cSDongdong Hao if (!leapraid_pci_active(adapter))
75535597088cSDongdong Hao return 0;
75545597088cSDongdong Hao
75555597088cSDongdong Hao count = 0;
75565597088cSDongdong Hao db = leapraid_readl(&adapter->iomem_base->db);
75575597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) == LEAPRAID_DB_RESET) {
75585597088cSDongdong Hao while ((db & LEAPRAID_DB_MASK) != LEAPRAID_DB_READY) {
75595597088cSDongdong Hao if (count++ == LEAPRAID_DB_RETRY_COUNT_MAX) {
75605597088cSDongdong Hao dev_err(&adapter->pdev->dev,
75615597088cSDongdong Hao "Wait adapter ready timeout\n");
75625597088cSDongdong Hao return -EFAULT;
75635597088cSDongdong Hao }
75645597088cSDongdong Hao ssleep(1);
75655597088cSDongdong Hao db = leapraid_readl(&adapter->iomem_base->db);
75665597088cSDongdong Hao dev_info(&adapter->pdev->dev,
75675597088cSDongdong Hao "Wait adapter ready, count=%d, db=0x%x\n",
75685597088cSDongdong Hao count, db);
75695597088cSDongdong Hao }
75705597088cSDongdong Hao }
75715597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) == LEAPRAID_DB_READY)
75725597088cSDongdong Hao return 0;
75735597088cSDongdong Hao
75745597088cSDongdong Hao if (db & LEAPRAID_DB_USED)
75755597088cSDongdong Hao goto full_reset;
75765597088cSDongdong Hao
75775597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) == LEAPRAID_DB_FAULT)
75785597088cSDongdong Hao goto full_reset;
75795597088cSDongdong Hao
75805597088cSDongdong Hao if (type == FULL_RESET)
75815597088cSDongdong Hao goto full_reset;
75825597088cSDongdong Hao
75835597088cSDongdong Hao if ((db & LEAPRAID_DB_MASK) == LEAPRAID_DB_OPERATIONAL &&
75845597088cSDongdong Hao !leapraid_adapter_unit_reset(adapter))
75855597088cSDongdong Hao return 0;
75865597088cSDongdong Hao
75875597088cSDongdong Hao full_reset:
75885597088cSDongdong Hao return leapraid_host_diag_reset(adapter);
75895597088cSDongdong Hao }
75905597088cSDongdong Hao
leapraid_fw_log_exit(struct leapraid_adapter * adapter)75915597088cSDongdong Hao static void leapraid_fw_log_exit(struct leapraid_adapter *adapter)
75925597088cSDongdong Hao {
75935597088cSDongdong Hao if (!adapter->fw_log_desc.open_pcie_trace)
75945597088cSDongdong Hao return;
75955597088cSDongdong Hao
75965597088cSDongdong Hao if (adapter->fw_log_desc.fw_log_buffer) {
75975597088cSDongdong Hao wait_event(adapter->fw_log_desc.mmap_waitq,
75985597088cSDongdong Hao !atomic_read(&adapter->fw_log_desc.mmap_refcnt));
75995597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev,
76005597088cSDongdong Hao (LEAPRAID_SYS_LOG_BUF_SIZE +
76015597088cSDongdong Hao LEAPRAID_SYS_LOG_BUF_RESERVE),
76025597088cSDongdong Hao adapter->fw_log_desc.fw_log_buffer,
76035597088cSDongdong Hao adapter->fw_log_desc.fw_log_buffer_dma);
76045597088cSDongdong Hao adapter->fw_log_desc.fw_log_buffer = NULL;
76055597088cSDongdong Hao }
76065597088cSDongdong Hao }
76075597088cSDongdong Hao
leapraid_fw_log_init(struct leapraid_adapter * adapter)76085597088cSDongdong Hao static int leapraid_fw_log_init(struct leapraid_adapter *adapter)
76095597088cSDongdong Hao {
76105597088cSDongdong Hao struct leapraid_adapter_log_req adapter_log_req;
76115597088cSDongdong Hao struct leapraid_adapter_log_rep adapter_log_rep;
76125597088cSDongdong Hao u16 adapter_status;
76135597088cSDongdong Hao u64 buf_addr;
76145597088cSDongdong Hao u32 rc;
76155597088cSDongdong Hao
76165597088cSDongdong Hao if (!adapter->fw_log_desc.open_pcie_trace)
76175597088cSDongdong Hao return 0;
76185597088cSDongdong Hao
76195597088cSDongdong Hao if (!adapter->fw_log_desc.fw_log_buffer) {
76205597088cSDongdong Hao adapter->fw_log_desc.fw_log_buffer =
76215597088cSDongdong Hao dma_alloc_coherent(
76225597088cSDongdong Hao &adapter->pdev->dev,
76235597088cSDongdong Hao (LEAPRAID_SYS_LOG_BUF_SIZE +
76245597088cSDongdong Hao LEAPRAID_SYS_LOG_BUF_RESERVE),
76255597088cSDongdong Hao &adapter->fw_log_desc.fw_log_buffer_dma,
76265597088cSDongdong Hao GFP_KERNEL);
76275597088cSDongdong Hao if (!adapter->fw_log_desc.fw_log_buffer)
76285597088cSDongdong Hao return -ENOMEM;
76295597088cSDongdong Hao }
76305597088cSDongdong Hao
76315597088cSDongdong Hao memset(&adapter_log_req, 0, sizeof(struct leapraid_adapter_log_req));
76325597088cSDongdong Hao adapter_log_req.func = LEAPRAID_FUNC_LOGBUF_INIT;
76335597088cSDongdong Hao buf_addr = adapter->fw_log_desc.fw_log_buffer_dma;
76345597088cSDongdong Hao
76355597088cSDongdong Hao adapter_log_req.mbox.w[0] =
76365597088cSDongdong Hao cpu_to_le32((u32)(buf_addr & 0xFFFFFFFF));
76375597088cSDongdong Hao adapter_log_req.mbox.w[1] =
76385597088cSDongdong Hao cpu_to_le32((u32)((buf_addr >> 32) & 0xFFFFFFFF));
76395597088cSDongdong Hao adapter_log_req.mbox.w[2] =
76405597088cSDongdong Hao cpu_to_le32(LEAPRAID_SYS_LOG_BUF_SIZE);
76415597088cSDongdong Hao rc = leapraid_handshake_func(adapter,
76425597088cSDongdong Hao sizeof(struct leapraid_adapter_log_req),
76435597088cSDongdong Hao (u32 *)&adapter_log_req,
76445597088cSDongdong Hao sizeof(struct leapraid_adapter_log_rep),
76455597088cSDongdong Hao (u16 *)&adapter_log_rep);
76465597088cSDongdong Hao if (rc != 0) {
76475597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: Handshake failed, rc=%d\n",
76485597088cSDongdong Hao __func__, rc);
76495597088cSDongdong Hao return rc;
76505597088cSDongdong Hao }
76515597088cSDongdong Hao
76525597088cSDongdong Hao adapter_status = le16_to_cpu(adapter_log_rep.adapter_status) &
76535597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
76545597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS) {
76555597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: failed!\n", __func__);
76565597088cSDongdong Hao rc = -EIO;
76575597088cSDongdong Hao }
76585597088cSDongdong Hao
76595597088cSDongdong Hao return rc;
76605597088cSDongdong Hao }
76615597088cSDongdong Hao
leapraid_free_host_memory(struct leapraid_adapter * adapter)76625597088cSDongdong Hao static void leapraid_free_host_memory(struct leapraid_adapter *adapter)
76635597088cSDongdong Hao {
76645597088cSDongdong Hao unsigned int i;
76655597088cSDongdong Hao
76665597088cSDongdong Hao if (adapter->mem_desc.task_desc) {
76675597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev,
76685597088cSDongdong Hao adapter->adapter_attr.task_desc_dma_size,
76695597088cSDongdong Hao adapter->mem_desc.task_desc,
76705597088cSDongdong Hao adapter->mem_desc.task_desc_dma);
76715597088cSDongdong Hao adapter->mem_desc.task_desc = NULL;
76725597088cSDongdong Hao }
76735597088cSDongdong Hao
76745597088cSDongdong Hao if (adapter->mem_desc.sense_data) {
76755597088cSDongdong Hao dma_free_coherent(
76765597088cSDongdong Hao &adapter->pdev->dev,
76775597088cSDongdong Hao adapter->adapter_attr.io_qd * SCSI_SENSE_BUFFERSIZE,
76785597088cSDongdong Hao adapter->mem_desc.sense_data,
76795597088cSDongdong Hao adapter->mem_desc.sense_data_dma);
76805597088cSDongdong Hao adapter->mem_desc.sense_data = NULL;
76815597088cSDongdong Hao }
76825597088cSDongdong Hao
76835597088cSDongdong Hao if (adapter->mem_desc.rep_msg) {
76845597088cSDongdong Hao dma_free_coherent(
76855597088cSDongdong Hao &adapter->pdev->dev,
76865597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd * LEAPRAID_REPLY_SIZE,
76875597088cSDongdong Hao adapter->mem_desc.rep_msg,
76885597088cSDongdong Hao adapter->mem_desc.rep_msg_dma);
76895597088cSDongdong Hao adapter->mem_desc.rep_msg = NULL;
76905597088cSDongdong Hao }
76915597088cSDongdong Hao
76925597088cSDongdong Hao if (adapter->mem_desc.rep_msg_addr) {
76935597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev,
76945597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd *
76955597088cSDongdong Hao LEAPRAID_REP_MSG_ADDR_SIZE,
76965597088cSDongdong Hao adapter->mem_desc.rep_msg_addr,
76975597088cSDongdong Hao adapter->mem_desc.rep_msg_addr_dma);
76985597088cSDongdong Hao adapter->mem_desc.rep_msg_addr = NULL;
76995597088cSDongdong Hao }
77005597088cSDongdong Hao
77015597088cSDongdong Hao if (adapter->mem_desc.rep_desc_seg_maint) {
77025597088cSDongdong Hao for (i = 0; i < adapter->adapter_attr.rep_desc_q_seg_cnt;
77035597088cSDongdong Hao i++) {
77045597088cSDongdong Hao if (adapter->mem_desc.rep_desc_seg_maint[i]
77055597088cSDongdong Hao .rep_desc_seg) {
77065597088cSDongdong Hao dma_free_coherent(
77075597088cSDongdong Hao &adapter->pdev->dev,
77085597088cSDongdong Hao (adapter->adapter_attr.rep_desc_qd *
77095597088cSDongdong Hao LEAPRAID_REP_DESC_ENTRY_SIZE) *
77105597088cSDongdong Hao LEAPRAID_REP_DESC_CHUNK_SIZE,
77115597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint[i]
77125597088cSDongdong Hao .rep_desc_seg,
77135597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint[i]
77145597088cSDongdong Hao .rep_desc_seg_dma);
77155597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint[i]
77165597088cSDongdong Hao .rep_desc_seg = NULL;
77175597088cSDongdong Hao }
77185597088cSDongdong Hao }
77195597088cSDongdong Hao
77205597088cSDongdong Hao if (adapter->mem_desc.rep_desc_q_arr) {
77215597088cSDongdong Hao dma_free_coherent(
77225597088cSDongdong Hao &adapter->pdev->dev,
77235597088cSDongdong Hao adapter->adapter_attr.rq_cnt *
77245597088cSDongdong Hao LEAPRAID_REP_RQ_CNT_SIZE,
77255597088cSDongdong Hao adapter->mem_desc.rep_desc_q_arr,
77265597088cSDongdong Hao adapter->mem_desc.rep_desc_q_arr_dma);
77275597088cSDongdong Hao adapter->mem_desc.rep_desc_q_arr = NULL;
77285597088cSDongdong Hao }
77295597088cSDongdong Hao
77305597088cSDongdong Hao for (i = 0; i < adapter->adapter_attr.rep_desc_q_seg_cnt; i++) {
77315597088cSDongdong Hao struct leapraid_mem_desc *mem_desc =
77325597088cSDongdong Hao &adapter->mem_desc;
77335597088cSDongdong Hao kfree(adapter->mem_desc.rep_desc_seg_maint[i]
77345597088cSDongdong Hao .rep_desc_maint);
77355597088cSDongdong Hao mem_desc->rep_desc_seg_maint[i].rep_desc_maint = NULL;
77365597088cSDongdong Hao }
77375597088cSDongdong Hao kfree(adapter->mem_desc.rep_desc_seg_maint);
77385597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint = NULL;
77395597088cSDongdong Hao }
77405597088cSDongdong Hao
77415597088cSDongdong Hao kfree(adapter->mem_desc.taskid_to_uniq_tag);
77425597088cSDongdong Hao adapter->mem_desc.taskid_to_uniq_tag = NULL;
77435597088cSDongdong Hao
77445597088cSDongdong Hao dma_pool_destroy(adapter->mem_desc.sg_chain_pool);
77455597088cSDongdong Hao adapter->mem_desc.sg_chain_pool = NULL;
77465597088cSDongdong Hao }
77475597088cSDongdong Hao
leapraid_is_in_same_4g_seg(dma_addr_t start,u32 size)77485597088cSDongdong Hao static inline bool leapraid_is_in_same_4g_seg(dma_addr_t start, u32 size)
77495597088cSDongdong Hao {
77505597088cSDongdong Hao return upper_32_bits(start) == upper_32_bits(start + size - 1);
77515597088cSDongdong Hao }
77525597088cSDongdong Hao
leapraid_internal_init_cmd_priv(struct leapraid_adapter * adapter,struct leapraid_io_req_tracker * io_tracker)77535597088cSDongdong Hao int leapraid_internal_init_cmd_priv(struct leapraid_adapter *adapter,
77545597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker)
77555597088cSDongdong Hao {
77565597088cSDongdong Hao io_tracker->chain =
77575597088cSDongdong Hao dma_pool_alloc(adapter->mem_desc.sg_chain_pool,
77585597088cSDongdong Hao GFP_KERNEL,
77595597088cSDongdong Hao &io_tracker->chain_dma);
77605597088cSDongdong Hao
77615597088cSDongdong Hao if (!io_tracker->chain)
77625597088cSDongdong Hao return -ENOMEM;
77635597088cSDongdong Hao
77645597088cSDongdong Hao return 0;
77655597088cSDongdong Hao }
77665597088cSDongdong Hao
leapraid_internal_exit_cmd_priv(struct leapraid_adapter * adapter,struct leapraid_io_req_tracker * io_tracker)77675597088cSDongdong Hao void leapraid_internal_exit_cmd_priv(struct leapraid_adapter *adapter,
77685597088cSDongdong Hao struct leapraid_io_req_tracker *io_tracker)
77695597088cSDongdong Hao {
77705597088cSDongdong Hao if (io_tracker && io_tracker->chain)
77715597088cSDongdong Hao dma_pool_free(adapter->mem_desc.sg_chain_pool,
77725597088cSDongdong Hao io_tracker->chain,
77735597088cSDongdong Hao io_tracker->chain_dma);
77745597088cSDongdong Hao }
77755597088cSDongdong Hao
leapraid_request_host_memory(struct leapraid_adapter * adapter)77765597088cSDongdong Hao static int leapraid_request_host_memory(struct leapraid_adapter *adapter)
77775597088cSDongdong Hao {
77785597088cSDongdong Hao struct leapraid_adapter_features *facts =
77795597088cSDongdong Hao &adapter->adapter_attr.features;
77805597088cSDongdong Hao u16 rep_desc_q_cnt_allocated;
77815597088cSDongdong Hao unsigned int i, j;
77825597088cSDongdong Hao int rc;
77835597088cSDongdong Hao
77845597088cSDongdong Hao /* Scatter-gather table size. */
77855597088cSDongdong Hao adapter->shost->sg_tablesize = LEAPRAID_SG_DEPTH;
77865597088cSDongdong Hao if (reset_devices)
77875597088cSDongdong Hao adapter->shost->sg_tablesize =
77885597088cSDongdong Hao LEAPRAID_KDUMP_MIN_PHYS_SEGMENTS;
77895597088cSDongdong Hao /* High-priority commands queue depth. */
77905597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd = LEAPRAID_FIXED_HP_CMDS;
77915597088cSDongdong Hao /* Internal commands queue depth. */
77925597088cSDongdong Hao adapter->dynamic_task_desc.inter_cmd_qd = LEAPRAID_FIXED_INTER_CMDS;
77935597088cSDongdong Hao /* Adapter commands total queue depth. */
77945597088cSDongdong Hao if (reset_devices)
77955597088cSDongdong Hao adapter->adapter_attr.adapter_total_qd =
77965597088cSDongdong Hao LEAPRAID_DEFAULT_CMD_QD_OFFSET +
77975597088cSDongdong Hao adapter->dynamic_task_desc.inter_cmd_qd +
77985597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd;
77995597088cSDongdong Hao else
78005597088cSDongdong Hao adapter->adapter_attr.adapter_total_qd = facts->req_slot +
78015597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd;
78025597088cSDongdong Hao /* Reply message queue depth. */
78035597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd =
78045597088cSDongdong Hao adapter->adapter_attr.adapter_total_qd +
78055597088cSDongdong Hao LEAPRAID_DEFAULT_CMD_QD_OFFSET;
78065597088cSDongdong Hao /* Reply descriptor queue depth. */
78075597088cSDongdong Hao adapter->adapter_attr.rep_desc_qd =
78085597088cSDongdong Hao round_up(adapter->adapter_attr.adapter_total_qd +
78095597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd +
78105597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_CTRL_CMD,
78115597088cSDongdong Hao LEAPRAID_REPLY_QD_ALIGNMENT);
78125597088cSDongdong Hao /* SCSI command I/O depth. */
78135597088cSDongdong Hao adapter->adapter_attr.io_qd =
78145597088cSDongdong Hao adapter->adapter_attr.adapter_total_qd -
78155597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd -
78165597088cSDongdong Hao adapter->dynamic_task_desc.inter_cmd_qd;
78175597088cSDongdong Hao /* SCSI host can queue. */
78185597088cSDongdong Hao adapter->shost->can_queue = adapter->adapter_attr.io_qd -
78195597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_CTRL_CMD;
78205597088cSDongdong Hao adapter->driver_cmds.ctl_cmd.taskid = adapter->shost->can_queue +
78215597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_CTRL_CMD;
78225597088cSDongdong Hao
78235597088cSDongdong Hao /* Allocate task descriptor. */
78245597088cSDongdong Hao try_again:
78255597088cSDongdong Hao adapter->adapter_attr.task_desc_dma_size =
78265597088cSDongdong Hao (adapter->adapter_attr.adapter_total_qd +
78275597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_CTRL_CMD) *
78285597088cSDongdong Hao LEAPRAID_REQUEST_SIZE;
78295597088cSDongdong Hao adapter->mem_desc.task_desc =
78305597088cSDongdong Hao dma_alloc_coherent(&adapter->pdev->dev,
78315597088cSDongdong Hao adapter->adapter_attr.task_desc_dma_size,
78325597088cSDongdong Hao &adapter->mem_desc.task_desc_dma,
78335597088cSDongdong Hao GFP_KERNEL);
78345597088cSDongdong Hao if (!adapter->mem_desc.task_desc)
78355597088cSDongdong Hao return -ENOMEM;
78365597088cSDongdong Hao
78375597088cSDongdong Hao /* Allocate chain message pool. */
78385597088cSDongdong Hao adapter->mem_desc.sg_chain_pool_size =
78395597088cSDongdong Hao LEAPRAID_DEFAULT_CHAINS_PER_IO * LEAPRAID_CHAIN_SEG_SIZE;
78405597088cSDongdong Hao adapter->mem_desc.sg_chain_pool =
78415597088cSDongdong Hao dma_pool_create("leapraid chain pool",
78425597088cSDongdong Hao &adapter->pdev->dev,
78435597088cSDongdong Hao adapter->mem_desc.sg_chain_pool_size,
78445597088cSDongdong Hao LEAPRAID_DMA_ALIGN, 0);
78455597088cSDongdong Hao if (!adapter->mem_desc.sg_chain_pool)
78465597088cSDongdong Hao return -ENOMEM;
78475597088cSDongdong Hao
78485597088cSDongdong Hao /* Allocate I/O tracker to SCSI I/O. */
78495597088cSDongdong Hao adapter->mem_desc.taskid_to_uniq_tag =
78505597088cSDongdong Hao kcalloc(adapter->shost->can_queue, sizeof(u16), GFP_KERNEL);
78515597088cSDongdong Hao if (!adapter->mem_desc.taskid_to_uniq_tag)
78525597088cSDongdong Hao return -ENOMEM;
78535597088cSDongdong Hao
78545597088cSDongdong Hao adapter->dynamic_task_desc.hp_taskid =
78555597088cSDongdong Hao adapter->adapter_attr.io_qd +
78565597088cSDongdong Hao LEAPRAID_HP_TASKID_OFFSET_CTL_CMD;
78575597088cSDongdong Hao /* Allocate static high-priority task ID. */
78585597088cSDongdong Hao adapter->driver_cmds.ctl_cmd.hp_taskid =
78595597088cSDongdong Hao adapter->dynamic_task_desc.hp_taskid;
78605597088cSDongdong Hao adapter->driver_cmds.tm_cmd.hp_taskid =
78615597088cSDongdong Hao adapter->dynamic_task_desc.hp_taskid +
78625597088cSDongdong Hao LEAPRAID_HP_TASKID_OFFSET_TM_CMD;
78635597088cSDongdong Hao
78645597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid =
78655597088cSDongdong Hao adapter->dynamic_task_desc.hp_taskid +
78665597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd;
78675597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.inter_taskid =
78685597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid;
78695597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.inter_taskid =
78705597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid +
78715597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_CFG_OP_CMD;
78725597088cSDongdong Hao adapter->driver_cmds.transport_cmd.inter_taskid =
78735597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid +
78745597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_TRANSPORT_CMD;
78755597088cSDongdong Hao adapter->driver_cmds.enc_cmd.inter_taskid =
78765597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid +
78775597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_ENC_CMD;
78785597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.inter_taskid =
78795597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid +
78805597088cSDongdong Hao LEAPRAID_TASKID_OFFSET_NOTIFY_EVENT_CMD;
78815597088cSDongdong Hao dev_info(&adapter->pdev->dev, "queue depth:\n");
78825597088cSDongdong Hao dev_info(&adapter->pdev->dev, " host->can_queue: %d\n",
78835597088cSDongdong Hao adapter->shost->can_queue);
78845597088cSDongdong Hao dev_info(&adapter->pdev->dev, " io_qd: %d\n",
78855597088cSDongdong Hao adapter->adapter_attr.io_qd);
78865597088cSDongdong Hao dev_info(&adapter->pdev->dev, " hpr_cmd_qd: %d\n",
78875597088cSDongdong Hao adapter->dynamic_task_desc.hp_cmd_qd);
78885597088cSDongdong Hao dev_info(&adapter->pdev->dev, " inter_cmd_qd: %d\n",
78895597088cSDongdong Hao adapter->dynamic_task_desc.inter_cmd_qd);
78905597088cSDongdong Hao dev_info(&adapter->pdev->dev, " adapter_total_qd: %d\n",
78915597088cSDongdong Hao adapter->adapter_attr.adapter_total_qd);
78925597088cSDongdong Hao
78935597088cSDongdong Hao dev_info(&adapter->pdev->dev, "taskid range:\n");
78945597088cSDongdong Hao dev_info(&adapter->pdev->dev,
78955597088cSDongdong Hao " adapter->dynamic_task_desc.hp_taskid: %d\n",
78965597088cSDongdong Hao adapter->dynamic_task_desc.hp_taskid);
78975597088cSDongdong Hao dev_info(&adapter->pdev->dev,
78985597088cSDongdong Hao " adapter->dynamic_task_desc.inter_taskid: %d\n",
78995597088cSDongdong Hao adapter->dynamic_task_desc.inter_taskid);
79005597088cSDongdong Hao
79015597088cSDongdong Hao /*
79025597088cSDongdong Hao * Allocate sense data DMA buffer.
79035597088cSDongdong Hao * Constraint: Must reside within the same 4GB segment
79045597088cSDongdong Hao * (driver-maintained).
79055597088cSDongdong Hao */
79065597088cSDongdong Hao adapter->mem_desc.sense_data =
79075597088cSDongdong Hao dma_alloc_coherent(
79085597088cSDongdong Hao &adapter->pdev->dev,
79095597088cSDongdong Hao adapter->adapter_attr.io_qd * SCSI_SENSE_BUFFERSIZE,
79105597088cSDongdong Hao &adapter->mem_desc.sense_data_dma,
79115597088cSDongdong Hao GFP_KERNEL);
79125597088cSDongdong Hao if (!adapter->mem_desc.sense_data)
79135597088cSDongdong Hao return -ENOMEM;
79145597088cSDongdong Hao
79155597088cSDongdong Hao if (!leapraid_is_in_same_4g_seg(adapter->mem_desc.sense_data_dma,
79165597088cSDongdong Hao adapter->adapter_attr.io_qd *
79175597088cSDongdong Hao SCSI_SENSE_BUFFERSIZE)) {
79185597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
79195597088cSDongdong Hao "Try 32bit DMA: Sense not in same 4G\n");
79205597088cSDongdong Hao rc = -EAGAIN;
79215597088cSDongdong Hao goto out_fail;
79225597088cSDongdong Hao }
79235597088cSDongdong Hao
79245597088cSDongdong Hao /*
79255597088cSDongdong Hao * Allocate reply frame buffer.
79265597088cSDongdong Hao * Constraint: Must reside in the same 4GB segment as the sense DMA.
79275597088cSDongdong Hao */
79285597088cSDongdong Hao adapter->mem_desc.rep_msg =
79295597088cSDongdong Hao dma_alloc_coherent(&adapter->pdev->dev,
79305597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd *
79315597088cSDongdong Hao LEAPRAID_REPLY_SIZE,
79325597088cSDongdong Hao &adapter->mem_desc.rep_msg_dma,
79335597088cSDongdong Hao GFP_KERNEL);
79345597088cSDongdong Hao if (!adapter->mem_desc.rep_msg) {
79355597088cSDongdong Hao rc = -ENOMEM;
79365597088cSDongdong Hao goto out_fail;
79375597088cSDongdong Hao }
79385597088cSDongdong Hao
79395597088cSDongdong Hao if (!leapraid_is_in_same_4g_seg(adapter->mem_desc.rep_msg_dma,
79405597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd *
79415597088cSDongdong Hao LEAPRAID_REPLY_SIZE)) {
79425597088cSDongdong Hao dev_warn(&adapter->pdev->dev,
79435597088cSDongdong Hao "Use 32 bit DMA due to rep msg is not in same 4g!\n");
79445597088cSDongdong Hao rc = -EAGAIN;
79455597088cSDongdong Hao goto out_fail;
79465597088cSDongdong Hao }
79475597088cSDongdong Hao
79485597088cSDongdong Hao /* Address of reply frame. */
79495597088cSDongdong Hao adapter->mem_desc.rep_msg_addr =
79505597088cSDongdong Hao dma_alloc_coherent(&adapter->pdev->dev,
79515597088cSDongdong Hao adapter->adapter_attr.rep_msg_qd *
79525597088cSDongdong Hao LEAPRAID_REP_MSG_ADDR_SIZE,
79535597088cSDongdong Hao &adapter->mem_desc.rep_msg_addr_dma,
79545597088cSDongdong Hao GFP_KERNEL);
79555597088cSDongdong Hao if (!adapter->mem_desc.rep_msg_addr)
79565597088cSDongdong Hao return -ENOMEM;
79575597088cSDongdong Hao adapter->adapter_attr.rep_desc_q_seg_cnt =
79585597088cSDongdong Hao DIV_ROUND_UP(adapter->adapter_attr.rq_cnt,
79595597088cSDongdong Hao LEAPRAID_REP_DESC_CHUNK_SIZE);
79605597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint =
79615597088cSDongdong Hao kcalloc(adapter->adapter_attr.rep_desc_q_seg_cnt,
79625597088cSDongdong Hao sizeof(struct leapraid_rep_desc_seg_maint),
79635597088cSDongdong Hao GFP_KERNEL);
79645597088cSDongdong Hao if (!adapter->mem_desc.rep_desc_seg_maint)
79655597088cSDongdong Hao return -ENOMEM;
79665597088cSDongdong Hao
79675597088cSDongdong Hao rep_desc_q_cnt_allocated = 0;
79685597088cSDongdong Hao for (i = 0; i < adapter->adapter_attr.rep_desc_q_seg_cnt; i++) {
79695597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint[i].rep_desc_maint =
79705597088cSDongdong Hao kcalloc(LEAPRAID_REP_DESC_CHUNK_SIZE,
79715597088cSDongdong Hao sizeof(struct leapraid_rep_desc_maint),
79725597088cSDongdong Hao GFP_KERNEL);
79735597088cSDongdong Hao if (!adapter->mem_desc.rep_desc_seg_maint[i].rep_desc_maint)
79745597088cSDongdong Hao return -ENOMEM;
79755597088cSDongdong Hao
79765597088cSDongdong Hao adapter->mem_desc.rep_desc_seg_maint[i].rep_desc_seg =
79775597088cSDongdong Hao dma_alloc_coherent(
79785597088cSDongdong Hao &adapter->pdev->dev,
79795597088cSDongdong Hao (adapter->adapter_attr.rep_desc_qd *
79805597088cSDongdong Hao LEAPRAID_REP_DESC_ENTRY_SIZE) *
79815597088cSDongdong Hao LEAPRAID_REP_DESC_CHUNK_SIZE,
79825597088cSDongdong Hao &adapter->mem_desc.rep_desc_seg_maint[i]
79835597088cSDongdong Hao .rep_desc_seg_dma,
79845597088cSDongdong Hao GFP_KERNEL);
79855597088cSDongdong Hao if (!adapter->mem_desc.rep_desc_seg_maint[i].rep_desc_seg)
79865597088cSDongdong Hao return -ENOMEM;
79875597088cSDongdong Hao
79885597088cSDongdong Hao for (j = 0; j < LEAPRAID_REP_DESC_CHUNK_SIZE; j++) {
79895597088cSDongdong Hao if (rep_desc_q_cnt_allocated >=
79905597088cSDongdong Hao adapter->adapter_attr.rq_cnt)
79915597088cSDongdong Hao break;
79925597088cSDongdong Hao adapter->mem_desc
79935597088cSDongdong Hao .rep_desc_seg_maint[i]
79945597088cSDongdong Hao .rep_desc_maint[j]
79955597088cSDongdong Hao .rep_desc =
79965597088cSDongdong Hao (void *)((u8 *)(
79975597088cSDongdong Hao adapter->mem_desc
79985597088cSDongdong Hao .rep_desc_seg_maint[i]
79995597088cSDongdong Hao .rep_desc_seg) +
80005597088cSDongdong Hao j *
80015597088cSDongdong Hao (adapter->adapter_attr.rep_desc_qd *
80025597088cSDongdong Hao LEAPRAID_REP_DESC_ENTRY_SIZE));
80035597088cSDongdong Hao adapter->mem_desc
80045597088cSDongdong Hao .rep_desc_seg_maint[i]
80055597088cSDongdong Hao .rep_desc_maint[j]
80065597088cSDongdong Hao .rep_desc_dma =
80075597088cSDongdong Hao adapter->mem_desc
80085597088cSDongdong Hao .rep_desc_seg_maint[i]
80095597088cSDongdong Hao .rep_desc_seg_dma +
80105597088cSDongdong Hao j *
80115597088cSDongdong Hao (adapter->adapter_attr.rep_desc_qd *
80125597088cSDongdong Hao LEAPRAID_REP_DESC_ENTRY_SIZE);
80135597088cSDongdong Hao rep_desc_q_cnt_allocated++;
80145597088cSDongdong Hao }
80155597088cSDongdong Hao }
80165597088cSDongdong Hao
80175597088cSDongdong Hao if (!reset_devices) {
80185597088cSDongdong Hao adapter->mem_desc.rep_desc_q_arr =
80195597088cSDongdong Hao dma_alloc_coherent(
80205597088cSDongdong Hao &adapter->pdev->dev,
80215597088cSDongdong Hao adapter->adapter_attr.rq_cnt *
80225597088cSDongdong Hao LEAPRAID_REP_RQ_CNT_SIZE,
80235597088cSDongdong Hao &adapter->mem_desc.rep_desc_q_arr_dma,
80245597088cSDongdong Hao GFP_KERNEL);
80255597088cSDongdong Hao if (!adapter->mem_desc.rep_desc_q_arr)
80265597088cSDongdong Hao return -ENOMEM;
80275597088cSDongdong Hao }
80285597088cSDongdong Hao
80295597088cSDongdong Hao return 0;
80305597088cSDongdong Hao out_fail:
80315597088cSDongdong Hao if (rc == -EAGAIN) {
80325597088cSDongdong Hao leapraid_free_host_memory(adapter);
80335597088cSDongdong Hao adapter->adapter_attr.use_32_dma_mask = 1;
80345597088cSDongdong Hao rc = dma_set_mask_and_coherent(&adapter->pdev->dev,
80355597088cSDongdong Hao DMA_BIT_MASK(DMA_32_BITS));
80365597088cSDongdong Hao if (rc) {
80375597088cSDongdong Hao dev_err(&adapter->pdev->dev,
80385597088cSDongdong Hao "Failed to set 32 DMA mask\n");
80395597088cSDongdong Hao return rc;
80405597088cSDongdong Hao }
80415597088cSDongdong Hao goto try_again;
80425597088cSDongdong Hao }
80435597088cSDongdong Hao return rc;
80445597088cSDongdong Hao }
80455597088cSDongdong Hao
leapraid_alloc_dev_topo_bitmaps(struct leapraid_adapter * adapter)80465597088cSDongdong Hao static int leapraid_alloc_dev_topo_bitmaps(struct leapraid_adapter *adapter)
80475597088cSDongdong Hao {
80485597088cSDongdong Hao u16 pd_hdls_sz;
80495597088cSDongdong Hao
80505597088cSDongdong Hao pd_hdls_sz =
80515597088cSDongdong Hao BITS_TO_LONGS(
80525597088cSDongdong Hao adapter->adapter_attr.features.max_dev_handle + 1) *
80535597088cSDongdong Hao sizeof(unsigned long);
80545597088cSDongdong Hao
80555597088cSDongdong Hao adapter->dev_topo.pd_hdls_sz = pd_hdls_sz;
80565597088cSDongdong Hao adapter->dev_topo.pd_hdls =
80575597088cSDongdong Hao kzalloc(adapter->dev_topo.pd_hdls_sz, GFP_KERNEL);
80585597088cSDongdong Hao if (!adapter->dev_topo.pd_hdls)
80595597088cSDongdong Hao return -ENOMEM;
80605597088cSDongdong Hao
80615597088cSDongdong Hao adapter->dev_topo.blocking_hdls =
80625597088cSDongdong Hao kzalloc(adapter->dev_topo.pd_hdls_sz, GFP_KERNEL);
80635597088cSDongdong Hao if (!adapter->dev_topo.blocking_hdls)
80645597088cSDongdong Hao return -ENOMEM;
80655597088cSDongdong Hao
80665597088cSDongdong Hao return 0;
80675597088cSDongdong Hao }
80685597088cSDongdong Hao
leapraid_free_dev_topo_bitmaps(struct leapraid_adapter * adapter)80695597088cSDongdong Hao static void leapraid_free_dev_topo_bitmaps(struct leapraid_adapter *adapter)
80705597088cSDongdong Hao {
80715597088cSDongdong Hao kfree(adapter->dev_topo.pd_hdls);
80725597088cSDongdong Hao kfree(adapter->dev_topo.blocking_hdls);
80735597088cSDongdong Hao }
80745597088cSDongdong Hao
leapraid_init_driver_cmds(struct leapraid_adapter * adapter)80755597088cSDongdong Hao static int leapraid_init_driver_cmds(struct leapraid_adapter *adapter)
80765597088cSDongdong Hao {
80775597088cSDongdong Hao INIT_LIST_HEAD(&adapter->driver_cmds.special_cmd_list);
80785597088cSDongdong Hao
80795597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status = LEAPRAID_CMD_NOT_USED;
80805597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.cb_idx = LEAPRAID_SCAN_DEV_CB_IDX;
80815597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.scan_dev_cmd.list,
80825597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
80835597088cSDongdong Hao
80845597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.status = LEAPRAID_CMD_NOT_USED;
80855597088cSDongdong Hao adapter->driver_cmds.cfg_op_cmd.cb_idx = LEAPRAID_CONFIG_CB_IDX;
80865597088cSDongdong Hao mutex_init(&adapter->driver_cmds.cfg_op_cmd.mutex);
80875597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.cfg_op_cmd.list,
80885597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
80895597088cSDongdong Hao
80905597088cSDongdong Hao adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_NOT_USED;
80915597088cSDongdong Hao adapter->driver_cmds.transport_cmd.cb_idx = LEAPRAID_TRANSPORT_CB_IDX;
80925597088cSDongdong Hao mutex_init(&adapter->driver_cmds.transport_cmd.mutex);
80935597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.transport_cmd.list,
80945597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
80955597088cSDongdong Hao
80965597088cSDongdong Hao adapter->driver_cmds.enc_cmd.status = LEAPRAID_CMD_NOT_USED;
80975597088cSDongdong Hao adapter->driver_cmds.enc_cmd.cb_idx = LEAPRAID_ENC_CB_IDX;
80985597088cSDongdong Hao mutex_init(&adapter->driver_cmds.enc_cmd.mutex);
80995597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.enc_cmd.list,
81005597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
81015597088cSDongdong Hao
81025597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.status = LEAPRAID_CMD_NOT_USED;
81035597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.cb_idx =
81045597088cSDongdong Hao LEAPRAID_NOTIFY_EVENT_CB_IDX;
81055597088cSDongdong Hao mutex_init(&adapter->driver_cmds.notify_event_cmd.mutex);
81065597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.notify_event_cmd.list,
81075597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
81085597088cSDongdong Hao
81095597088cSDongdong Hao adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_NOT_USED;
81105597088cSDongdong Hao adapter->driver_cmds.ctl_cmd.cb_idx = LEAPRAID_CTL_CB_IDX;
81115597088cSDongdong Hao mutex_init(&adapter->driver_cmds.ctl_cmd.mutex);
81125597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.ctl_cmd.list,
81135597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
81145597088cSDongdong Hao
81155597088cSDongdong Hao adapter->driver_cmds.tm_cmd.status = LEAPRAID_CMD_NOT_USED;
81165597088cSDongdong Hao adapter->driver_cmds.tm_cmd.cb_idx = LEAPRAID_TM_CB_IDX;
81175597088cSDongdong Hao mutex_init(&adapter->driver_cmds.tm_cmd.mutex);
81185597088cSDongdong Hao list_add_tail(&adapter->driver_cmds.tm_cmd.list,
81195597088cSDongdong Hao &adapter->driver_cmds.special_cmd_list);
81205597088cSDongdong Hao
81215597088cSDongdong Hao return 0;
81225597088cSDongdong Hao }
81235597088cSDongdong Hao
leapraid_unmask_evts(struct leapraid_adapter * adapter,u16 evt)81245597088cSDongdong Hao static void leapraid_unmask_evts(struct leapraid_adapter *adapter, u16 evt)
81255597088cSDongdong Hao {
81265597088cSDongdong Hao if (evt >= LEAPRAID_MAX_EVENT_NUM)
81275597088cSDongdong Hao return;
81285597088cSDongdong Hao
81295597088cSDongdong Hao clear_bit(evt, (unsigned long *)adapter->fw_evt_s.leapraid_evt_masks);
81305597088cSDongdong Hao }
81315597088cSDongdong Hao
leapraid_init_event_mask(struct leapraid_adapter * adapter)81325597088cSDongdong Hao static void leapraid_init_event_mask(struct leapraid_adapter *adapter)
81335597088cSDongdong Hao {
81345597088cSDongdong Hao int i;
81355597088cSDongdong Hao
81365597088cSDongdong Hao for (i = 0; i < LEAPRAID_EVT_MASK_COUNT; i++)
81375597088cSDongdong Hao adapter->fw_evt_s.leapraid_evt_masks[i] =
81385597088cSDongdong Hao LEAPRAID_INVALID_INITIAL_VALUE;
81395597088cSDongdong Hao
81405597088cSDongdong Hao leapraid_unmask_evts(adapter, LEAPRAID_EVT_SAS_TOPO_CHANGE_LIST);
81415597088cSDongdong Hao leapraid_unmask_evts(adapter, LEAPRAID_EVT_SAS_ENCL_DEV_STATUS_CHANGE);
81425597088cSDongdong Hao leapraid_unmask_evts(adapter, LEAPRAID_EVT_SAS_DEV_STATUS_CHANGE);
81435597088cSDongdong Hao leapraid_unmask_evts(adapter, LEAPRAID_EVT_IR_CHANGE);
81445597088cSDongdong Hao }
81455597088cSDongdong Hao
leapraid_prepare_adapter_init_req(struct leapraid_adapter * adapter,struct leapraid_adapter_init_req * init_req)81465597088cSDongdong Hao static void leapraid_prepare_adapter_init_req(
81475597088cSDongdong Hao struct leapraid_adapter *adapter,
81485597088cSDongdong Hao struct leapraid_adapter_init_req *init_req)
81495597088cSDongdong Hao {
81505597088cSDongdong Hao ktime_t cur_time;
81515597088cSDongdong Hao int i, chunk;
81525597088cSDongdong Hao u32 reply_post_free_ary_sz;
81535597088cSDongdong Hao
81545597088cSDongdong Hao memset(init_req, 0, sizeof(struct leapraid_adapter_init_req));
81555597088cSDongdong Hao init_req->func = LEAPRAID_FUNC_ADAPTER_INIT;
81565597088cSDongdong Hao init_req->who_init = LEAPRAID_WHOINIT_LINUX_DRIVER;
81575597088cSDongdong Hao init_req->msg_ver = cpu_to_le16(LEAPRAID_MSG_VERSION);
81585597088cSDongdong Hao init_req->header_ver = cpu_to_le16(LEAPRAID_HEADER_VERSION);
81595597088cSDongdong Hao init_req->driver_ver =
81605597088cSDongdong Hao cpu_to_le32((LEAPRAID_MAJOR_VERSION <<
81615597088cSDongdong Hao LEAPRAID_VER_MAJOR_SHIFT) |
81625597088cSDongdong Hao (LEAPRAID_MINOR_VERSION << LEAPRAID_VER_MINOR_SHIFT) |
81635597088cSDongdong Hao (LEAPRAID_BUILD_VERSION << LEAPRAID_VER_BUILD_SHIFT) |
81645597088cSDongdong Hao LEAPRAID_RELEASE_VERSION);
81655597088cSDongdong Hao if (adapter->notification_desc.msix_enable)
81665597088cSDongdong Hao init_req->host_msix_vectors = adapter->adapter_attr.rq_cnt;
81675597088cSDongdong Hao
81685597088cSDongdong Hao init_req->req_frame_size =
81695597088cSDongdong Hao cpu_to_le16(LEAPRAID_REQUEST_SIZE / LEAPRAID_DWORDS_BYTE_SIZE);
81705597088cSDongdong Hao init_req->rep_desc_qd =
81715597088cSDongdong Hao cpu_to_le16(adapter->adapter_attr.rep_desc_qd);
81725597088cSDongdong Hao init_req->rep_msg_qd =
81735597088cSDongdong Hao cpu_to_le16(adapter->adapter_attr.rep_msg_qd);
81745597088cSDongdong Hao init_req->sense_buffer_add_high =
81755597088cSDongdong Hao cpu_to_le32((u64)adapter->mem_desc.sense_data_dma >> 32);
81765597088cSDongdong Hao init_req->rep_msg_dma_high =
81775597088cSDongdong Hao cpu_to_le32((u64)adapter->mem_desc.rep_msg_dma >> 32);
81785597088cSDongdong Hao init_req->task_desc_base_addr =
81795597088cSDongdong Hao cpu_to_le64((u64)adapter->mem_desc.task_desc_dma);
81805597088cSDongdong Hao init_req->rep_msg_addr_dma =
81815597088cSDongdong Hao cpu_to_le64((u64)adapter->mem_desc.rep_msg_addr_dma);
81825597088cSDongdong Hao if (!reset_devices) {
81835597088cSDongdong Hao reply_post_free_ary_sz =
81845597088cSDongdong Hao adapter->adapter_attr.rq_cnt * LEAPRAID_REP_RQ_CNT_SIZE;
81855597088cSDongdong Hao memset(adapter->mem_desc.rep_desc_q_arr, 0,
81865597088cSDongdong Hao reply_post_free_ary_sz);
81875597088cSDongdong Hao
81885597088cSDongdong Hao chunk = LEAPRAID_REP_DESC_CHUNK_SIZE;
81895597088cSDongdong Hao for (i = 0; i < adapter->adapter_attr.rq_cnt; i++)
81905597088cSDongdong Hao adapter->mem_desc.rep_desc_q_arr[i].rep_desc_base_addr =
81915597088cSDongdong Hao cpu_to_le64 ((u64)adapter->mem_desc
81925597088cSDongdong Hao .rep_desc_seg_maint[i / chunk]
81935597088cSDongdong Hao .rep_desc_maint[i % chunk]
81945597088cSDongdong Hao .rep_desc_dma);
81955597088cSDongdong Hao
81965597088cSDongdong Hao init_req->msg_flg =
81975597088cSDongdong Hao LEAPRAID_ADAPTER_INIT_MSGFLG_RDPQ_ARRAY_MODE;
81985597088cSDongdong Hao init_req->rep_desc_q_arr_addr =
81995597088cSDongdong Hao cpu_to_le64((u64)adapter->mem_desc.rep_desc_q_arr_dma);
82005597088cSDongdong Hao } else {
82015597088cSDongdong Hao init_req->rep_desc_q_arr_addr =
82025597088cSDongdong Hao cpu_to_le64((u64)adapter->mem_desc
82035597088cSDongdong Hao .rep_desc_seg_maint[0]
82045597088cSDongdong Hao .rep_desc_maint[0]
82055597088cSDongdong Hao .rep_desc_dma);
82065597088cSDongdong Hao }
82075597088cSDongdong Hao cur_time = ktime_get_real();
82085597088cSDongdong Hao init_req->time_stamp = cpu_to_le64(ktime_to_ms(cur_time));
82095597088cSDongdong Hao }
82105597088cSDongdong Hao
leapraid_send_adapter_init(struct leapraid_adapter * adapter)82115597088cSDongdong Hao static int leapraid_send_adapter_init(struct leapraid_adapter *adapter)
82125597088cSDongdong Hao {
82135597088cSDongdong Hao struct leapraid_adapter_init_req init_req;
82145597088cSDongdong Hao struct leapraid_adapter_init_rep init_rep;
82155597088cSDongdong Hao u16 adapter_status;
82165597088cSDongdong Hao int rc;
82175597088cSDongdong Hao
82185597088cSDongdong Hao leapraid_prepare_adapter_init_req(adapter, &init_req);
82195597088cSDongdong Hao
82205597088cSDongdong Hao rc = leapraid_handshake_func(adapter,
82215597088cSDongdong Hao sizeof(struct leapraid_adapter_init_req),
82225597088cSDongdong Hao (u32 *)&init_req,
82235597088cSDongdong Hao sizeof(struct leapraid_adapter_init_rep),
82245597088cSDongdong Hao (u16 *)&init_rep);
82255597088cSDongdong Hao if (rc != 0) {
82265597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: Handshake failed, rc=%d\n",
82275597088cSDongdong Hao __func__, rc);
82285597088cSDongdong Hao return rc;
82295597088cSDongdong Hao }
82305597088cSDongdong Hao
82315597088cSDongdong Hao adapter_status =
82325597088cSDongdong Hao le16_to_cpu(init_rep.adapter_status) &
82335597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
82345597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS) {
82355597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: failed\n", __func__);
82365597088cSDongdong Hao rc = -EIO;
82375597088cSDongdong Hao }
82385597088cSDongdong Hao
82395597088cSDongdong Hao return rc;
82405597088cSDongdong Hao }
82415597088cSDongdong Hao
leapraid_cfg_pages(struct leapraid_adapter * adapter)82425597088cSDongdong Hao static int leapraid_cfg_pages(struct leapraid_adapter *adapter)
82435597088cSDongdong Hao {
82445597088cSDongdong Hao union cfg_param_1 cfgp1 = {0};
82455597088cSDongdong Hao union cfg_param_2 cfgp2 = {0};
82465597088cSDongdong Hao union {
82475597088cSDongdong Hao struct leapraid_manufacturing_p0 manufacturing_page0;
82485597088cSDongdong Hao struct leapraid_bios_page3 bios_page3;
82495597088cSDongdong Hao struct leapraid_bios_page2 bios_page2;
82505597088cSDongdong Hao } cfg_page;
82515597088cSDongdong Hao int rc;
82525597088cSDongdong Hao
82535597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &cfg_page.bios_page3, cfgp1,
82545597088cSDongdong Hao cfgp2, GET_BIOS_PG3);
82555597088cSDongdong Hao if (rc)
82565597088cSDongdong Hao return rc;
82575597088cSDongdong Hao
82585597088cSDongdong Hao adapter->adapter_attr.bios_version =
82595597088cSDongdong Hao le32_to_cpu(cfg_page.bios_page3.bios_version);
82605597088cSDongdong Hao
82615597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &cfg_page.bios_page2, cfgp1,
82625597088cSDongdong Hao cfgp2, GET_BIOS_PG2);
82635597088cSDongdong Hao if (rc)
82645597088cSDongdong Hao return rc;
82655597088cSDongdong Hao
82665597088cSDongdong Hao adapter->boot_devs.requested_boot_dev.form =
82675597088cSDongdong Hao cfg_page.bios_page2.requested_boot_dev_form;
82685597088cSDongdong Hao memcpy(adapter->boot_devs.requested_boot_dev.pg_dev,
82695597088cSDongdong Hao &cfg_page.bios_page2.requested_boot_dev,
82705597088cSDongdong Hao LEAPRAID_BOOT_DEV_SIZE);
82715597088cSDongdong Hao adapter->boot_devs.requested_alt_boot_dev.form =
82725597088cSDongdong Hao cfg_page.bios_page2.requested_alt_boot_dev_form;
82735597088cSDongdong Hao memcpy(adapter->boot_devs.requested_alt_boot_dev.pg_dev,
82745597088cSDongdong Hao &cfg_page.bios_page2.requested_alt_boot_dev,
82755597088cSDongdong Hao LEAPRAID_BOOT_DEV_SIZE);
82765597088cSDongdong Hao adapter->boot_devs.current_boot_dev.form =
82775597088cSDongdong Hao cfg_page.bios_page2.current_boot_dev_form;
82785597088cSDongdong Hao memcpy(adapter->boot_devs.current_boot_dev.pg_dev,
82795597088cSDongdong Hao &cfg_page.bios_page2.current_boot_dev,
82805597088cSDongdong Hao LEAPRAID_BOOT_DEV_SIZE);
82815597088cSDongdong Hao
82825597088cSDongdong Hao rc = leapraid_op_config_page(adapter, &cfg_page.manufacturing_page0,
82835597088cSDongdong Hao cfgp1, cfgp2, GET_MANUFACTURING_PG0);
82845597088cSDongdong Hao if (rc)
82855597088cSDongdong Hao return rc;
82865597088cSDongdong Hao
82875597088cSDongdong Hao snprintf(adapter->adapter_attr.board_name,
82885597088cSDongdong Hao sizeof(adapter->adapter_attr.board_name),
82895597088cSDongdong Hao "%.*s",
82905597088cSDongdong Hao (int)sizeof(cfg_page.manufacturing_page0.board_name),
82915597088cSDongdong Hao cfg_page.manufacturing_page0.board_name);
82925597088cSDongdong Hao return rc;
82935597088cSDongdong Hao }
82945597088cSDongdong Hao
leapraid_evt_notify(struct leapraid_adapter * adapter)82955597088cSDongdong Hao static int leapraid_evt_notify(struct leapraid_adapter *adapter)
82965597088cSDongdong Hao {
82975597088cSDongdong Hao struct leapraid_evt_notify_req *evt_notify_req;
82985597088cSDongdong Hao struct leapraid_evt_notify_rep *evt_notify_rep;
82995597088cSDongdong Hao u16 adapter_status;
83005597088cSDongdong Hao int rc = 0;
83015597088cSDongdong Hao int i;
83025597088cSDongdong Hao
83035597088cSDongdong Hao mutex_lock(&adapter->driver_cmds.notify_event_cmd.mutex);
83045597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.status = LEAPRAID_CMD_PENDING;
83055597088cSDongdong Hao evt_notify_req =
83065597088cSDongdong Hao leapraid_get_task_desc(
83075597088cSDongdong Hao adapter,
83085597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.inter_taskid);
83095597088cSDongdong Hao memset(evt_notify_req, 0, sizeof(struct leapraid_evt_notify_req));
83105597088cSDongdong Hao evt_notify_req->func = LEAPRAID_FUNC_EVENT_NOTIFY;
83115597088cSDongdong Hao for (i = 0; i < LEAPRAID_EVT_MASK_COUNT; i++)
83125597088cSDongdong Hao evt_notify_req->evt_masks[i] =
83135597088cSDongdong Hao cpu_to_le32(adapter->fw_evt_s.leapraid_evt_masks[i]);
83145597088cSDongdong Hao init_completion(&adapter->driver_cmds.notify_event_cmd.done);
83155597088cSDongdong Hao leapraid_fire_task(adapter,
83165597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.inter_taskid);
83175597088cSDongdong Hao wait_for_completion_timeout(
83185597088cSDongdong Hao &adapter->driver_cmds.notify_event_cmd.done,
83195597088cSDongdong Hao LEAPRAID_NOTIFY_EVENT_CMD_TIMEOUT * HZ);
83205597088cSDongdong Hao
83215597088cSDongdong Hao if (!(adapter->driver_cmds.notify_event_cmd.status &
83225597088cSDongdong Hao LEAPRAID_CMD_DONE)) {
83235597088cSDongdong Hao rc = -EFAULT;
83245597088cSDongdong Hao goto out_cleanup;
83255597088cSDongdong Hao }
83265597088cSDongdong Hao
83275597088cSDongdong Hao if (!(adapter->driver_cmds.notify_event_cmd.status &
83285597088cSDongdong Hao LEAPRAID_CMD_REPLY_VALID)) {
83295597088cSDongdong Hao rc = -EFAULT;
83305597088cSDongdong Hao goto out_cleanup;
83315597088cSDongdong Hao }
83325597088cSDongdong Hao
83335597088cSDongdong Hao evt_notify_rep = (void *)&adapter->driver_cmds.notify_event_cmd.reply;
83345597088cSDongdong Hao adapter_status = le16_to_cpu(evt_notify_rep->adapter_status) &
83355597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
83365597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS)
83375597088cSDongdong Hao rc = -EFAULT;
83385597088cSDongdong Hao
83395597088cSDongdong Hao out_cleanup:
83405597088cSDongdong Hao adapter->driver_cmds.notify_event_cmd.status = LEAPRAID_CMD_NOT_USED;
83415597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.notify_event_cmd.mutex);
83425597088cSDongdong Hao
83435597088cSDongdong Hao return rc;
83445597088cSDongdong Hao }
83455597088cSDongdong Hao
leapraid_scan_dev(struct leapraid_adapter * adapter,bool async_scan_dev)83465597088cSDongdong Hao int leapraid_scan_dev(struct leapraid_adapter *adapter, bool async_scan_dev)
83475597088cSDongdong Hao {
83485597088cSDongdong Hao struct leapraid_scan_dev_req *scan_dev_req;
83495597088cSDongdong Hao struct leapraid_scan_dev_rep *scan_dev_rep;
83505597088cSDongdong Hao u16 adapter_status;
83515597088cSDongdong Hao int rc = 0;
83525597088cSDongdong Hao
83535597088cSDongdong Hao dev_info(&adapter->pdev->dev,
83545597088cSDongdong Hao "Send device scan, async_scan_dev=%d!\n", async_scan_dev);
83555597088cSDongdong Hao
83565597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status = LEAPRAID_CMD_PENDING;
83575597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.async_scan_dev = async_scan_dev;
83585597088cSDongdong Hao scan_dev_req =
83595597088cSDongdong Hao leapraid_get_task_desc(
83605597088cSDongdong Hao adapter,
83615597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.inter_taskid);
83625597088cSDongdong Hao memset(scan_dev_req, 0, sizeof(struct leapraid_scan_dev_req));
83635597088cSDongdong Hao scan_dev_req->func = LEAPRAID_FUNC_SCAN_DEV;
83645597088cSDongdong Hao
83655597088cSDongdong Hao if (async_scan_dev) {
83665597088cSDongdong Hao adapter->scan_dev_desc.first_scan_dev_fired = 1;
83675597088cSDongdong Hao leapraid_fire_task(
83685597088cSDongdong Hao adapter,
83695597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.inter_taskid);
83705597088cSDongdong Hao return 0;
83715597088cSDongdong Hao }
83725597088cSDongdong Hao
83735597088cSDongdong Hao init_completion(&adapter->driver_cmds.scan_dev_cmd.done);
83745597088cSDongdong Hao leapraid_fire_task(adapter,
83755597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.inter_taskid);
83765597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.scan_dev_cmd.done,
83775597088cSDongdong Hao LEAPRAID_SCAN_DEV_CMD_TIMEOUT * HZ);
83785597088cSDongdong Hao if (!(adapter->driver_cmds.scan_dev_cmd.status & LEAPRAID_CMD_DONE)) {
83795597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Device scan timeout!\n");
83805597088cSDongdong Hao if (adapter->driver_cmds.scan_dev_cmd.status &
83815597088cSDongdong Hao LEAPRAID_CMD_RESET)
83825597088cSDongdong Hao rc = -EFAULT;
83835597088cSDongdong Hao else
83845597088cSDongdong Hao rc = -ETIME;
83855597088cSDongdong Hao goto out_cleanup;
83865597088cSDongdong Hao }
83875597088cSDongdong Hao
83885597088cSDongdong Hao scan_dev_rep = (void *)&adapter->driver_cmds.scan_dev_cmd.reply;
83895597088cSDongdong Hao adapter_status =
83905597088cSDongdong Hao le16_to_cpu(scan_dev_rep->adapter_status) &
83915597088cSDongdong Hao LEAPRAID_ADAPTER_STATUS_MASK;
83925597088cSDongdong Hao if (adapter_status != LEAPRAID_ADAPTER_STATUS_SUCCESS) {
83935597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Device scan failure!\n");
83945597088cSDongdong Hao rc = -EFAULT;
83955597088cSDongdong Hao goto out_cleanup;
83965597088cSDongdong Hao }
83975597088cSDongdong Hao
83985597088cSDongdong Hao out_cleanup:
83995597088cSDongdong Hao adapter->driver_cmds.scan_dev_cmd.status = LEAPRAID_CMD_NOT_USED;
84005597088cSDongdong Hao return rc;
84015597088cSDongdong Hao }
84025597088cSDongdong Hao
leapraid_init_task_tracker(struct leapraid_adapter * adapter)84035597088cSDongdong Hao static void leapraid_init_task_tracker(struct leapraid_adapter *adapter)
84045597088cSDongdong Hao {
84055597088cSDongdong Hao unsigned long flags;
84065597088cSDongdong Hao
84075597088cSDongdong Hao spin_lock_irqsave(&adapter->dynamic_task_desc.task_lock, flags);
84085597088cSDongdong Hao
84095597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dynamic_task_desc.task_lock, flags);
84105597088cSDongdong Hao }
84115597088cSDongdong Hao
leapraid_init_rep_msg_addr(struct leapraid_adapter * adapter)84125597088cSDongdong Hao static void leapraid_init_rep_msg_addr(struct leapraid_adapter *adapter)
84135597088cSDongdong Hao {
84145597088cSDongdong Hao u32 reply_address;
84155597088cSDongdong Hao unsigned int i;
84165597088cSDongdong Hao
84175597088cSDongdong Hao for (i = 0, reply_address = (u32)adapter->mem_desc.rep_msg_dma;
84185597088cSDongdong Hao i < adapter->adapter_attr.rep_msg_qd;
84195597088cSDongdong Hao i++, reply_address += LEAPRAID_REPLY_SIZE)
84205597088cSDongdong Hao adapter->mem_desc.rep_msg_addr[i] = cpu_to_le32(reply_address);
84215597088cSDongdong Hao }
84225597088cSDongdong Hao
init_rep_desc(struct leapraid_rq * rq,int index,union leapraid_rep_desc_union * reply_post_free_contig)84235597088cSDongdong Hao static void init_rep_desc(
84245597088cSDongdong Hao struct leapraid_rq *rq,
84255597088cSDongdong Hao int index,
84265597088cSDongdong Hao union leapraid_rep_desc_union *reply_post_free_contig)
84275597088cSDongdong Hao {
84285597088cSDongdong Hao struct leapraid_adapter *adapter = rq->adapter;
84295597088cSDongdong Hao unsigned int i;
84305597088cSDongdong Hao
84315597088cSDongdong Hao if (!reset_devices)
84325597088cSDongdong Hao rq->rep_desc =
84335597088cSDongdong Hao adapter->mem_desc
84345597088cSDongdong Hao .rep_desc_seg_maint[index /
84355597088cSDongdong Hao LEAPRAID_REP_DESC_CHUNK_SIZE]
84365597088cSDongdong Hao .rep_desc_maint[index %
84375597088cSDongdong Hao LEAPRAID_REP_DESC_CHUNK_SIZE]
84385597088cSDongdong Hao .rep_desc;
84395597088cSDongdong Hao else
84405597088cSDongdong Hao rq->rep_desc = reply_post_free_contig;
84415597088cSDongdong Hao
84425597088cSDongdong Hao rq->rep_post_host_idx = 0;
84435597088cSDongdong Hao for (i = 0; i < adapter->adapter_attr.rep_desc_qd; i++)
84445597088cSDongdong Hao rq->rep_desc[i].words = cpu_to_le64(ULLONG_MAX);
84455597088cSDongdong Hao }
84465597088cSDongdong Hao
leapraid_init_rep_desc(struct leapraid_adapter * adapter)84475597088cSDongdong Hao static void leapraid_init_rep_desc(struct leapraid_adapter *adapter)
84485597088cSDongdong Hao {
84495597088cSDongdong Hao union leapraid_rep_desc_union *reply_post_free_contig;
84505597088cSDongdong Hao struct leapraid_int_rq *int_rq;
84515597088cSDongdong Hao struct leapraid_blk_mq_poll_rq *blk_mq_poll_rq;
84525597088cSDongdong Hao unsigned int i;
84535597088cSDongdong Hao int index;
84545597088cSDongdong Hao
84555597088cSDongdong Hao index = 0;
84565597088cSDongdong Hao reply_post_free_contig = adapter->mem_desc
84575597088cSDongdong Hao .rep_desc_seg_maint[0]
84585597088cSDongdong Hao .rep_desc_maint[0]
84595597088cSDongdong Hao .rep_desc;
84605597088cSDongdong Hao
84615597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qdex; i++) {
84625597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[i];
84635597088cSDongdong Hao init_rep_desc(&int_rq->rq, index, reply_post_free_contig);
84645597088cSDongdong Hao if (!reset_devices)
84655597088cSDongdong Hao index++;
84665597088cSDongdong Hao else
84675597088cSDongdong Hao reply_post_free_contig +=
84685597088cSDongdong Hao adapter->adapter_attr.rep_desc_qd;
84695597088cSDongdong Hao }
84705597088cSDongdong Hao
84715597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qcnt; i++) {
84725597088cSDongdong Hao blk_mq_poll_rq = &adapter->notification_desc.blk_mq_poll_rqs[i];
84735597088cSDongdong Hao init_rep_desc(&blk_mq_poll_rq->rq,
84745597088cSDongdong Hao index, reply_post_free_contig);
84755597088cSDongdong Hao if (!reset_devices)
84765597088cSDongdong Hao index++;
84775597088cSDongdong Hao else
84785597088cSDongdong Hao reply_post_free_contig +=
84795597088cSDongdong Hao adapter->adapter_attr.rep_desc_qd;
84805597088cSDongdong Hao }
84815597088cSDongdong Hao }
84825597088cSDongdong Hao
leapraid_init_bar_idx_regs(struct leapraid_adapter * adapter)84835597088cSDongdong Hao static void leapraid_init_bar_idx_regs(struct leapraid_adapter *adapter)
84845597088cSDongdong Hao {
84855597088cSDongdong Hao struct leapraid_int_rq *int_rq;
84865597088cSDongdong Hao struct leapraid_blk_mq_poll_rq *blk_mq_poll_rq;
84875597088cSDongdong Hao unsigned int i, j;
84885597088cSDongdong Hao
84895597088cSDongdong Hao adapter->rep_msg_host_idx = adapter->adapter_attr.rep_msg_qd - 1;
84905597088cSDongdong Hao writel(adapter->rep_msg_host_idx,
84915597088cSDongdong Hao &adapter->iomem_base->rep_msg_host_idx);
84925597088cSDongdong Hao
84935597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qdex; i++) {
84945597088cSDongdong Hao int_rq = &adapter->notification_desc.int_rqs[i];
84955597088cSDongdong Hao for (j = 0; j < REP_POST_HOST_IDX_REG_CNT; j++)
84965597088cSDongdong Hao writel((int_rq->rq.msix_idx & 7) <<
84975597088cSDongdong Hao LEAPRAID_RPHI_MSIX_IDX_SHIFT,
84985597088cSDongdong Hao &adapter->iomem_base->rep_post_reg_idx[j].idx);
84995597088cSDongdong Hao }
85005597088cSDongdong Hao
85015597088cSDongdong Hao for (i = 0; i < adapter->notification_desc.iopoll_qcnt; i++) {
85025597088cSDongdong Hao blk_mq_poll_rq =
85035597088cSDongdong Hao &adapter->notification_desc.blk_mq_poll_rqs[i];
85045597088cSDongdong Hao for (j = 0; j < REP_POST_HOST_IDX_REG_CNT; j++)
85055597088cSDongdong Hao writel((blk_mq_poll_rq->rq.msix_idx & 7) <<
85065597088cSDongdong Hao LEAPRAID_RPHI_MSIX_IDX_SHIFT,
85075597088cSDongdong Hao &adapter->iomem_base->rep_post_reg_idx[j].idx);
85085597088cSDongdong Hao }
85095597088cSDongdong Hao }
85105597088cSDongdong Hao
leapraid_make_adapter_available(struct leapraid_adapter * adapter)85115597088cSDongdong Hao static int leapraid_make_adapter_available(struct leapraid_adapter *adapter)
85125597088cSDongdong Hao {
85135597088cSDongdong Hao int rc;
85145597088cSDongdong Hao
85155597088cSDongdong Hao leapraid_init_task_tracker(adapter);
85165597088cSDongdong Hao leapraid_init_rep_msg_addr(adapter);
85175597088cSDongdong Hao
85185597088cSDongdong Hao if (adapter->scan_dev_desc.driver_loading)
85195597088cSDongdong Hao leapraid_configure_reply_queue_affinity(adapter);
85205597088cSDongdong Hao
85215597088cSDongdong Hao leapraid_init_rep_desc(adapter);
85225597088cSDongdong Hao rc = leapraid_send_adapter_init(adapter);
85235597088cSDongdong Hao if (rc)
85245597088cSDongdong Hao return rc;
85255597088cSDongdong Hao
85265597088cSDongdong Hao leapraid_init_bar_idx_regs(adapter);
85275597088cSDongdong Hao leapraid_unmask_int(adapter);
85285597088cSDongdong Hao rc = leapraid_cfg_pages(adapter);
85295597088cSDongdong Hao if (rc)
85305597088cSDongdong Hao return rc;
85315597088cSDongdong Hao
85325597088cSDongdong Hao rc = leapraid_evt_notify(adapter);
85335597088cSDongdong Hao if (rc)
85345597088cSDongdong Hao return rc;
85355597088cSDongdong Hao
85365597088cSDongdong Hao if (!adapter->access_ctrl.shost_recovering) {
85375597088cSDongdong Hao adapter->scan_dev_desc.wait_scan_dev_done = 1;
85385597088cSDongdong Hao return 0;
85395597088cSDongdong Hao }
85405597088cSDongdong Hao
85415597088cSDongdong Hao return leapraid_scan_dev(adapter, false);
85425597088cSDongdong Hao }
85435597088cSDongdong Hao
leapraid_ctrl_init(struct leapraid_adapter * adapter)85445597088cSDongdong Hao int leapraid_ctrl_init(struct leapraid_adapter *adapter)
85455597088cSDongdong Hao {
85465597088cSDongdong Hao u32 cap;
85475597088cSDongdong Hao int rc;
85485597088cSDongdong Hao
85495597088cSDongdong Hao rc = leapraid_init_driver_cmds(adapter);
85505597088cSDongdong Hao if (rc) {
85515597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Init driver cmds failure\n");
85525597088cSDongdong Hao goto out_free;
85535597088cSDongdong Hao }
85545597088cSDongdong Hao
85555597088cSDongdong Hao rc = leapraid_set_pcie_and_notification(adapter);
85565597088cSDongdong Hao if (rc)
85575597088cSDongdong Hao goto out_free;
85585597088cSDongdong Hao
85595597088cSDongdong Hao pci_set_drvdata(adapter->pdev, adapter->shost);
85605597088cSDongdong Hao
85615597088cSDongdong Hao pcie_capability_read_dword(adapter->pdev, PCI_EXP_DEVCAP, &cap);
85625597088cSDongdong Hao
85635597088cSDongdong Hao if (cap & PCI_EXP_DEVCAP_EXT_TAG)
85645597088cSDongdong Hao pcie_capability_set_word(adapter->pdev, PCI_EXP_DEVCTL,
85655597088cSDongdong Hao PCI_EXP_DEVCTL_EXT_TAG);
85665597088cSDongdong Hao
85675597088cSDongdong Hao rc = leapraid_fw_log_init(adapter);
85685597088cSDongdong Hao if (rc) {
85695597088cSDongdong Hao dev_err(&adapter->pdev->dev, "FW log init failure\n");
85705597088cSDongdong Hao goto out_free;
85715597088cSDongdong Hao }
85725597088cSDongdong Hao
85735597088cSDongdong Hao rc = leapraid_request_host_memory(adapter);
85745597088cSDongdong Hao if (rc) {
85755597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Request host memory failure\n");
85765597088cSDongdong Hao goto out_free;
85775597088cSDongdong Hao }
85785597088cSDongdong Hao
85795597088cSDongdong Hao init_waitqueue_head(&adapter->reset_desc.reset_wait_queue);
85805597088cSDongdong Hao init_waitqueue_head(&adapter->access_ctrl.shost_recover_wq);
85815597088cSDongdong Hao
85825597088cSDongdong Hao rc = leapraid_alloc_dev_topo_bitmaps(adapter);
85835597088cSDongdong Hao if (rc) {
85845597088cSDongdong Hao dev_err(&adapter->pdev->dev, "Alloc topo bitmaps failure\n");
85855597088cSDongdong Hao goto out_free;
85865597088cSDongdong Hao }
85875597088cSDongdong Hao
85885597088cSDongdong Hao leapraid_init_event_mask(adapter);
85895597088cSDongdong Hao
85905597088cSDongdong Hao rc = leapraid_make_adapter_available(adapter);
85915597088cSDongdong Hao if (rc) {
85925597088cSDongdong Hao dev_err(&adapter->pdev->dev,
85935597088cSDongdong Hao "Make adapter available failure\n");
85945597088cSDongdong Hao goto out_free;
85955597088cSDongdong Hao }
85965597088cSDongdong Hao
85975597088cSDongdong Hao leapraid_overheat_init(adapter);
85985597088cSDongdong Hao if (!adapter->overheat_desc.fault_overheat_wq) {
85995597088cSDongdong Hao rc = -ENOMEM;
86005597088cSDongdong Hao goto out_free;
86015597088cSDongdong Hao }
86025597088cSDongdong Hao
86035597088cSDongdong Hao return 0;
86045597088cSDongdong Hao
86055597088cSDongdong Hao out_free:
86065597088cSDongdong Hao adapter->access_ctrl.host_removing = 1;
86075597088cSDongdong Hao leapraid_fw_log_exit(adapter);
86085597088cSDongdong Hao leapraid_disable_controller(adapter);
86095597088cSDongdong Hao leapraid_free_host_memory(adapter);
86105597088cSDongdong Hao leapraid_free_dev_topo_bitmaps(adapter);
86115597088cSDongdong Hao pci_set_drvdata(adapter->pdev, NULL);
86125597088cSDongdong Hao return rc;
86135597088cSDongdong Hao }
86145597088cSDongdong Hao
leapraid_remove_ctrl(struct leapraid_adapter * adapter)86155597088cSDongdong Hao void leapraid_remove_ctrl(struct leapraid_adapter *adapter)
86165597088cSDongdong Hao {
86175597088cSDongdong Hao leapraid_overheat_cleanup(adapter);
86185597088cSDongdong Hao leapraid_check_scheduled_fault_stop(adapter);
86195597088cSDongdong Hao leapraid_fw_log_stop(adapter);
86205597088cSDongdong Hao leapraid_fw_log_exit(adapter);
86215597088cSDongdong Hao leapraid_disable_controller(adapter);
86225597088cSDongdong Hao leapraid_free_host_memory(adapter);
86235597088cSDongdong Hao leapraid_free_dev_topo_bitmaps(adapter);
86245597088cSDongdong Hao leapraid_free_enc_list(adapter);
86255597088cSDongdong Hao pci_set_drvdata(adapter->pdev, NULL);
86265597088cSDongdong Hao }
8627