126780d9eSBradley Grove /* 226780d9eSBradley Grove * linux/drivers/scsi/esas2r/esas2r_init.c 326780d9eSBradley Grove * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers 426780d9eSBradley Grove * 526780d9eSBradley Grove * Copyright (c) 2001-2013 ATTO Technology, Inc. 626780d9eSBradley Grove * (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag. 726780d9eSBradley Grove * 826780d9eSBradley Grove * This program is free software; you can redistribute it and/or 926780d9eSBradley Grove * modify it under the terms of the GNU General Public License 1026780d9eSBradley Grove * as published by the Free Software Foundation; either version 2 1126780d9eSBradley Grove * of the License, or (at your option) any later version. 1226780d9eSBradley Grove * 1326780d9eSBradley Grove * This program is distributed in the hope that it will be useful, 1426780d9eSBradley Grove * but WITHOUT ANY WARRANTY; without even the implied warranty of 1526780d9eSBradley Grove * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1626780d9eSBradley Grove * GNU General Public License for more details. 1726780d9eSBradley Grove * 1826780d9eSBradley Grove * NO WARRANTY 1926780d9eSBradley Grove * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2026780d9eSBradley Grove * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2126780d9eSBradley Grove * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2226780d9eSBradley Grove * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2326780d9eSBradley Grove * solely responsible for determining the appropriateness of using and 2426780d9eSBradley Grove * distributing the Program and assumes all risks associated with its 2526780d9eSBradley Grove * exercise of rights under this Agreement, including but not limited to 2626780d9eSBradley Grove * the risks and costs of program errors, damage to or loss of data, 2726780d9eSBradley Grove * programs or equipment, and unavailability or interruption of operations. 2826780d9eSBradley Grove * 2926780d9eSBradley Grove * DISCLAIMER OF LIABILITY 3026780d9eSBradley Grove * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3126780d9eSBradley Grove * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3226780d9eSBradley Grove * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3326780d9eSBradley Grove * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3426780d9eSBradley Grove * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3526780d9eSBradley Grove * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 3626780d9eSBradley Grove * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 3726780d9eSBradley Grove * 3826780d9eSBradley Grove * You should have received a copy of the GNU General Public License 3926780d9eSBradley Grove * along with this program; if not, write to the Free Software 4026780d9eSBradley Grove * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 4126780d9eSBradley Grove * USA. 4226780d9eSBradley Grove */ 4326780d9eSBradley Grove 4426780d9eSBradley Grove #include "esas2r.h" 4526780d9eSBradley Grove 4626780d9eSBradley Grove static bool esas2r_initmem_alloc(struct esas2r_adapter *a, 4726780d9eSBradley Grove struct esas2r_mem_desc *mem_desc, 4826780d9eSBradley Grove u32 align) 4926780d9eSBradley Grove { 5026780d9eSBradley Grove mem_desc->esas2r_param = mem_desc->size + align; 5126780d9eSBradley Grove mem_desc->virt_addr = NULL; 5226780d9eSBradley Grove mem_desc->phys_addr = 0; 5326780d9eSBradley Grove mem_desc->esas2r_data = dma_alloc_coherent(&a->pcid->dev, 5426780d9eSBradley Grove (size_t)mem_desc-> 5526780d9eSBradley Grove esas2r_param, 5626780d9eSBradley Grove (dma_addr_t *)&mem_desc-> 5726780d9eSBradley Grove phys_addr, 5826780d9eSBradley Grove GFP_KERNEL); 5926780d9eSBradley Grove 6026780d9eSBradley Grove if (mem_desc->esas2r_data == NULL) { 6126780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 6226780d9eSBradley Grove "failed to allocate %lu bytes of consistent memory!", 6326780d9eSBradley Grove (long 6426780d9eSBradley Grove unsigned 6526780d9eSBradley Grove int)mem_desc->esas2r_param); 6626780d9eSBradley Grove return false; 6726780d9eSBradley Grove } 6826780d9eSBradley Grove 6926780d9eSBradley Grove mem_desc->virt_addr = PTR_ALIGN(mem_desc->esas2r_data, align); 7026780d9eSBradley Grove mem_desc->phys_addr = ALIGN(mem_desc->phys_addr, align); 7126780d9eSBradley Grove memset(mem_desc->virt_addr, 0, mem_desc->size); 7226780d9eSBradley Grove return true; 7326780d9eSBradley Grove } 7426780d9eSBradley Grove 7526780d9eSBradley Grove static void esas2r_initmem_free(struct esas2r_adapter *a, 7626780d9eSBradley Grove struct esas2r_mem_desc *mem_desc) 7726780d9eSBradley Grove { 7826780d9eSBradley Grove if (mem_desc->virt_addr == NULL) 7926780d9eSBradley Grove return; 8026780d9eSBradley Grove 8126780d9eSBradley Grove /* 8226780d9eSBradley Grove * Careful! phys_addr and virt_addr may have been adjusted from the 8326780d9eSBradley Grove * original allocation in order to return the desired alignment. That 8426780d9eSBradley Grove * means we have to use the original address (in esas2r_data) and size 8526780d9eSBradley Grove * (esas2r_param) and calculate the original physical address based on 8626780d9eSBradley Grove * the difference between the requested and actual allocation size. 8726780d9eSBradley Grove */ 8826780d9eSBradley Grove if (mem_desc->phys_addr) { 8926780d9eSBradley Grove int unalign = ((u8 *)mem_desc->virt_addr) - 9026780d9eSBradley Grove ((u8 *)mem_desc->esas2r_data); 9126780d9eSBradley Grove 9226780d9eSBradley Grove dma_free_coherent(&a->pcid->dev, 9326780d9eSBradley Grove (size_t)mem_desc->esas2r_param, 9426780d9eSBradley Grove mem_desc->esas2r_data, 9526780d9eSBradley Grove (dma_addr_t)(mem_desc->phys_addr - unalign)); 9626780d9eSBradley Grove } else { 9726780d9eSBradley Grove kfree(mem_desc->esas2r_data); 9826780d9eSBradley Grove } 9926780d9eSBradley Grove 10026780d9eSBradley Grove mem_desc->virt_addr = NULL; 10126780d9eSBradley Grove } 10226780d9eSBradley Grove 10326780d9eSBradley Grove static bool alloc_vda_req(struct esas2r_adapter *a, 10426780d9eSBradley Grove struct esas2r_request *rq) 10526780d9eSBradley Grove { 10626780d9eSBradley Grove struct esas2r_mem_desc *memdesc = kzalloc( 10726780d9eSBradley Grove sizeof(struct esas2r_mem_desc), GFP_KERNEL); 10826780d9eSBradley Grove 10926780d9eSBradley Grove if (memdesc == NULL) { 11026780d9eSBradley Grove esas2r_hdebug("could not alloc mem for vda request memdesc\n"); 11126780d9eSBradley Grove return false; 11226780d9eSBradley Grove } 11326780d9eSBradley Grove 11426780d9eSBradley Grove memdesc->size = sizeof(union atto_vda_req) + 11526780d9eSBradley Grove ESAS2R_DATA_BUF_LEN; 11626780d9eSBradley Grove 11726780d9eSBradley Grove if (!esas2r_initmem_alloc(a, memdesc, 256)) { 11826780d9eSBradley Grove esas2r_hdebug("could not alloc mem for vda request\n"); 11926780d9eSBradley Grove kfree(memdesc); 12026780d9eSBradley Grove return false; 12126780d9eSBradley Grove } 12226780d9eSBradley Grove 12326780d9eSBradley Grove a->num_vrqs++; 12426780d9eSBradley Grove list_add(&memdesc->next_desc, &a->vrq_mds_head); 12526780d9eSBradley Grove 12626780d9eSBradley Grove rq->vrq_md = memdesc; 12726780d9eSBradley Grove rq->vrq = (union atto_vda_req *)memdesc->virt_addr; 12826780d9eSBradley Grove rq->vrq->scsi.handle = a->num_vrqs; 12926780d9eSBradley Grove 13026780d9eSBradley Grove return true; 13126780d9eSBradley Grove } 13226780d9eSBradley Grove 13326780d9eSBradley Grove static void esas2r_unmap_regions(struct esas2r_adapter *a) 13426780d9eSBradley Grove { 13526780d9eSBradley Grove if (a->regs) 13626780d9eSBradley Grove iounmap((void __iomem *)a->regs); 13726780d9eSBradley Grove 13826780d9eSBradley Grove a->regs = NULL; 13926780d9eSBradley Grove 14026780d9eSBradley Grove pci_release_region(a->pcid, 2); 14126780d9eSBradley Grove 14226780d9eSBradley Grove if (a->data_window) 14326780d9eSBradley Grove iounmap((void __iomem *)a->data_window); 14426780d9eSBradley Grove 14526780d9eSBradley Grove a->data_window = NULL; 14626780d9eSBradley Grove 14726780d9eSBradley Grove pci_release_region(a->pcid, 0); 14826780d9eSBradley Grove } 14926780d9eSBradley Grove 15026780d9eSBradley Grove static int esas2r_map_regions(struct esas2r_adapter *a) 15126780d9eSBradley Grove { 15226780d9eSBradley Grove int error; 15326780d9eSBradley Grove 15426780d9eSBradley Grove a->regs = NULL; 15526780d9eSBradley Grove a->data_window = NULL; 15626780d9eSBradley Grove 15726780d9eSBradley Grove error = pci_request_region(a->pcid, 2, a->name); 15826780d9eSBradley Grove if (error != 0) { 15926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 16026780d9eSBradley Grove "pci_request_region(2) failed, error %d", 16126780d9eSBradley Grove error); 16226780d9eSBradley Grove 16326780d9eSBradley Grove return error; 16426780d9eSBradley Grove } 16526780d9eSBradley Grove 16626780d9eSBradley Grove a->regs = (void __force *)ioremap(pci_resource_start(a->pcid, 2), 16726780d9eSBradley Grove pci_resource_len(a->pcid, 2)); 16826780d9eSBradley Grove if (a->regs == NULL) { 16926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 17026780d9eSBradley Grove "ioremap failed for regs mem region\n"); 17126780d9eSBradley Grove pci_release_region(a->pcid, 2); 17226780d9eSBradley Grove return -EFAULT; 17326780d9eSBradley Grove } 17426780d9eSBradley Grove 17526780d9eSBradley Grove error = pci_request_region(a->pcid, 0, a->name); 17626780d9eSBradley Grove if (error != 0) { 17726780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 17826780d9eSBradley Grove "pci_request_region(2) failed, error %d", 17926780d9eSBradley Grove error); 18026780d9eSBradley Grove esas2r_unmap_regions(a); 18126780d9eSBradley Grove return error; 18226780d9eSBradley Grove } 18326780d9eSBradley Grove 18426780d9eSBradley Grove a->data_window = (void __force *)ioremap(pci_resource_start(a->pcid, 18526780d9eSBradley Grove 0), 18626780d9eSBradley Grove pci_resource_len(a->pcid, 0)); 18726780d9eSBradley Grove if (a->data_window == NULL) { 18826780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 18926780d9eSBradley Grove "ioremap failed for data_window mem region\n"); 19026780d9eSBradley Grove esas2r_unmap_regions(a); 19126780d9eSBradley Grove return -EFAULT; 19226780d9eSBradley Grove } 19326780d9eSBradley Grove 19426780d9eSBradley Grove return 0; 19526780d9eSBradley Grove } 19626780d9eSBradley Grove 19726780d9eSBradley Grove static void esas2r_setup_interrupts(struct esas2r_adapter *a, int intr_mode) 19826780d9eSBradley Grove { 19926780d9eSBradley Grove int i; 20026780d9eSBradley Grove 20126780d9eSBradley Grove /* Set up interrupt mode based on the requested value */ 20226780d9eSBradley Grove switch (intr_mode) { 20326780d9eSBradley Grove case INTR_MODE_LEGACY: 20426780d9eSBradley Grove use_legacy_interrupts: 20526780d9eSBradley Grove a->intr_mode = INTR_MODE_LEGACY; 20626780d9eSBradley Grove break; 20726780d9eSBradley Grove 20826780d9eSBradley Grove case INTR_MODE_MSI: 20926780d9eSBradley Grove i = pci_enable_msi(a->pcid); 21026780d9eSBradley Grove if (i != 0) { 21126780d9eSBradley Grove esas2r_log(ESAS2R_LOG_WARN, 21226780d9eSBradley Grove "failed to enable MSI for adapter %d, " 21326780d9eSBradley Grove "falling back to legacy interrupts " 21426780d9eSBradley Grove "(err=%d)", a->index, 21526780d9eSBradley Grove i); 21626780d9eSBradley Grove goto use_legacy_interrupts; 21726780d9eSBradley Grove } 21826780d9eSBradley Grove a->intr_mode = INTR_MODE_MSI; 2199588d24eSBradley Grove set_bit(AF2_MSI_ENABLED, &a->flags2); 22026780d9eSBradley Grove break; 22126780d9eSBradley Grove 22226780d9eSBradley Grove 22326780d9eSBradley Grove default: 22426780d9eSBradley Grove esas2r_log(ESAS2R_LOG_WARN, 22526780d9eSBradley Grove "unknown interrupt_mode %d requested, " 22626780d9eSBradley Grove "falling back to legacy interrupt", 22726780d9eSBradley Grove interrupt_mode); 22826780d9eSBradley Grove goto use_legacy_interrupts; 22926780d9eSBradley Grove } 23026780d9eSBradley Grove } 23126780d9eSBradley Grove 23226780d9eSBradley Grove static void esas2r_claim_interrupts(struct esas2r_adapter *a) 23326780d9eSBradley Grove { 2344909cc2bSMichael Opdenacker unsigned long flags = 0; 23526780d9eSBradley Grove 23626780d9eSBradley Grove if (a->intr_mode == INTR_MODE_LEGACY) 23726780d9eSBradley Grove flags |= IRQF_SHARED; 23826780d9eSBradley Grove 23926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_INFO, 24026780d9eSBradley Grove "esas2r_claim_interrupts irq=%d (%p, %s, %x)", 24126780d9eSBradley Grove a->pcid->irq, a, a->name, flags); 24226780d9eSBradley Grove 24326780d9eSBradley Grove if (request_irq(a->pcid->irq, 24426780d9eSBradley Grove (a->intr_mode == 24526780d9eSBradley Grove INTR_MODE_LEGACY) ? esas2r_interrupt : 24626780d9eSBradley Grove esas2r_msi_interrupt, 24726780d9eSBradley Grove flags, 24826780d9eSBradley Grove a->name, 24926780d9eSBradley Grove a)) { 25026780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "unable to request IRQ %02X", 25126780d9eSBradley Grove a->pcid->irq); 25226780d9eSBradley Grove return; 25326780d9eSBradley Grove } 25426780d9eSBradley Grove 2559588d24eSBradley Grove set_bit(AF2_IRQ_CLAIMED, &a->flags2); 25626780d9eSBradley Grove esas2r_log(ESAS2R_LOG_INFO, 25726780d9eSBradley Grove "claimed IRQ %d flags: 0x%lx", 25826780d9eSBradley Grove a->pcid->irq, flags); 25926780d9eSBradley Grove } 26026780d9eSBradley Grove 26126780d9eSBradley Grove int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid, 26226780d9eSBradley Grove int index) 26326780d9eSBradley Grove { 26426780d9eSBradley Grove struct esas2r_adapter *a; 26526780d9eSBradley Grove u64 bus_addr = 0; 26626780d9eSBradley Grove int i; 26726780d9eSBradley Grove void *next_uncached; 26826780d9eSBradley Grove struct esas2r_request *first_request, *last_request; 26926780d9eSBradley Grove 27026780d9eSBradley Grove if (index >= MAX_ADAPTERS) { 27126780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 27226780d9eSBradley Grove "tried to init invalid adapter index %u!", 27326780d9eSBradley Grove index); 27426780d9eSBradley Grove return 0; 27526780d9eSBradley Grove } 27626780d9eSBradley Grove 27726780d9eSBradley Grove if (esas2r_adapters[index]) { 27826780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 27926780d9eSBradley Grove "tried to init existing adapter index %u!", 28026780d9eSBradley Grove index); 28126780d9eSBradley Grove return 0; 28226780d9eSBradley Grove } 28326780d9eSBradley Grove 28426780d9eSBradley Grove a = (struct esas2r_adapter *)host->hostdata; 28526780d9eSBradley Grove memset(a, 0, sizeof(struct esas2r_adapter)); 28626780d9eSBradley Grove a->pcid = pcid; 28726780d9eSBradley Grove a->host = host; 28826780d9eSBradley Grove 28926780d9eSBradley Grove if (sizeof(dma_addr_t) > 4) { 29026780d9eSBradley Grove const uint64_t required_mask = dma_get_required_mask 29126780d9eSBradley Grove (&pcid->dev); 29226780d9eSBradley Grove if (required_mask > DMA_BIT_MASK(32) 29326780d9eSBradley Grove && !pci_set_dma_mask(pcid, DMA_BIT_MASK(64)) 29426780d9eSBradley Grove && !pci_set_consistent_dma_mask(pcid, 29526780d9eSBradley Grove DMA_BIT_MASK(64))) { 29626780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 29726780d9eSBradley Grove &(a->pcid->dev), 29826780d9eSBradley Grove "64-bit PCI addressing enabled\n"); 29926780d9eSBradley Grove } else if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32)) 30026780d9eSBradley Grove && !pci_set_consistent_dma_mask(pcid, 30126780d9eSBradley Grove DMA_BIT_MASK(32))) { 30226780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 30326780d9eSBradley Grove &(a->pcid->dev), 30426780d9eSBradley Grove "32-bit PCI addressing enabled\n"); 30526780d9eSBradley Grove } else { 30626780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 30726780d9eSBradley Grove "failed to set DMA mask"); 30826780d9eSBradley Grove esas2r_kill_adapter(index); 30926780d9eSBradley Grove return 0; 31026780d9eSBradley Grove } 31126780d9eSBradley Grove } else { 31226780d9eSBradley Grove if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32)) 31326780d9eSBradley Grove && !pci_set_consistent_dma_mask(pcid, 31426780d9eSBradley Grove DMA_BIT_MASK(32))) { 31526780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 31626780d9eSBradley Grove &(a->pcid->dev), 31726780d9eSBradley Grove "32-bit PCI addressing enabled\n"); 31826780d9eSBradley Grove } else { 31926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 32026780d9eSBradley Grove "failed to set DMA mask"); 32126780d9eSBradley Grove esas2r_kill_adapter(index); 32226780d9eSBradley Grove return 0; 32326780d9eSBradley Grove } 32426780d9eSBradley Grove } 32526780d9eSBradley Grove esas2r_adapters[index] = a; 32626780d9eSBradley Grove sprintf(a->name, ESAS2R_DRVR_NAME "_%02d", index); 32726780d9eSBradley Grove esas2r_debug("new adapter %p, name %s", a, a->name); 32826780d9eSBradley Grove spin_lock_init(&a->request_lock); 32926780d9eSBradley Grove spin_lock_init(&a->fw_event_lock); 33026780d9eSBradley Grove sema_init(&a->fm_api_semaphore, 1); 33126780d9eSBradley Grove sema_init(&a->fs_api_semaphore, 1); 33226780d9eSBradley Grove sema_init(&a->nvram_semaphore, 1); 33326780d9eSBradley Grove 33426780d9eSBradley Grove esas2r_fw_event_off(a); 33526780d9eSBradley Grove snprintf(a->fw_event_q_name, ESAS2R_KOBJ_NAME_LEN, "esas2r/%d", 33626780d9eSBradley Grove a->index); 33726780d9eSBradley Grove a->fw_event_q = create_singlethread_workqueue(a->fw_event_q_name); 33826780d9eSBradley Grove 33926780d9eSBradley Grove init_waitqueue_head(&a->buffered_ioctl_waiter); 34026780d9eSBradley Grove init_waitqueue_head(&a->nvram_waiter); 34126780d9eSBradley Grove init_waitqueue_head(&a->fm_api_waiter); 34226780d9eSBradley Grove init_waitqueue_head(&a->fs_api_waiter); 34326780d9eSBradley Grove init_waitqueue_head(&a->vda_waiter); 34426780d9eSBradley Grove 34526780d9eSBradley Grove INIT_LIST_HEAD(&a->general_req.req_list); 34626780d9eSBradley Grove INIT_LIST_HEAD(&a->active_list); 34726780d9eSBradley Grove INIT_LIST_HEAD(&a->defer_list); 34826780d9eSBradley Grove INIT_LIST_HEAD(&a->free_sg_list_head); 34926780d9eSBradley Grove INIT_LIST_HEAD(&a->avail_request); 35026780d9eSBradley Grove INIT_LIST_HEAD(&a->vrq_mds_head); 35126780d9eSBradley Grove INIT_LIST_HEAD(&a->fw_event_list); 35226780d9eSBradley Grove 35326780d9eSBradley Grove first_request = (struct esas2r_request *)((u8 *)(a + 1)); 35426780d9eSBradley Grove 35526780d9eSBradley Grove for (last_request = first_request, i = 1; i < num_requests; 35626780d9eSBradley Grove last_request++, i++) { 35726780d9eSBradley Grove INIT_LIST_HEAD(&last_request->req_list); 35826780d9eSBradley Grove list_add_tail(&last_request->comp_list, &a->avail_request); 35926780d9eSBradley Grove if (!alloc_vda_req(a, last_request)) { 36026780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 36126780d9eSBradley Grove "failed to allocate a VDA request!"); 36226780d9eSBradley Grove esas2r_kill_adapter(index); 36326780d9eSBradley Grove return 0; 36426780d9eSBradley Grove } 36526780d9eSBradley Grove } 36626780d9eSBradley Grove 36726780d9eSBradley Grove esas2r_debug("requests: %p to %p (%d, %d)", first_request, 36826780d9eSBradley Grove last_request, 36926780d9eSBradley Grove sizeof(*first_request), 37026780d9eSBradley Grove num_requests); 37126780d9eSBradley Grove 37226780d9eSBradley Grove if (esas2r_map_regions(a) != 0) { 37326780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "could not map PCI regions!"); 37426780d9eSBradley Grove esas2r_kill_adapter(index); 37526780d9eSBradley Grove return 0; 37626780d9eSBradley Grove } 37726780d9eSBradley Grove 37826780d9eSBradley Grove a->index = index; 37926780d9eSBradley Grove 38026780d9eSBradley Grove /* interrupts will be disabled until we are done with init */ 38126780d9eSBradley Grove atomic_inc(&a->dis_ints_cnt); 38226780d9eSBradley Grove atomic_inc(&a->disable_cnt); 3839588d24eSBradley Grove set_bit(AF_CHPRST_PENDING, &a->flags); 3849588d24eSBradley Grove set_bit(AF_DISC_PENDING, &a->flags); 3859588d24eSBradley Grove set_bit(AF_FIRST_INIT, &a->flags); 3869588d24eSBradley Grove set_bit(AF_LEGACY_SGE_MODE, &a->flags); 38726780d9eSBradley Grove 38826780d9eSBradley Grove a->init_msg = ESAS2R_INIT_MSG_START; 38926780d9eSBradley Grove a->max_vdareq_size = 128; 39026780d9eSBradley Grove a->build_sgl = esas2r_build_sg_list_sge; 39126780d9eSBradley Grove 39226780d9eSBradley Grove esas2r_setup_interrupts(a, interrupt_mode); 39326780d9eSBradley Grove 39426780d9eSBradley Grove a->uncached_size = esas2r_get_uncached_size(a); 39526780d9eSBradley Grove a->uncached = dma_alloc_coherent(&pcid->dev, 39626780d9eSBradley Grove (size_t)a->uncached_size, 39726780d9eSBradley Grove (dma_addr_t *)&bus_addr, 39826780d9eSBradley Grove GFP_KERNEL); 39926780d9eSBradley Grove if (a->uncached == NULL) { 40026780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 40126780d9eSBradley Grove "failed to allocate %d bytes of consistent memory!", 40226780d9eSBradley Grove a->uncached_size); 40326780d9eSBradley Grove esas2r_kill_adapter(index); 40426780d9eSBradley Grove return 0; 40526780d9eSBradley Grove } 40626780d9eSBradley Grove 40726780d9eSBradley Grove a->uncached_phys = bus_addr; 40826780d9eSBradley Grove 40926780d9eSBradley Grove esas2r_debug("%d bytes uncached memory allocated @ %p (%x:%x)", 41026780d9eSBradley Grove a->uncached_size, 41126780d9eSBradley Grove a->uncached, 41226780d9eSBradley Grove upper_32_bits(bus_addr), 41326780d9eSBradley Grove lower_32_bits(bus_addr)); 41426780d9eSBradley Grove memset(a->uncached, 0, a->uncached_size); 41526780d9eSBradley Grove next_uncached = a->uncached; 41626780d9eSBradley Grove 41726780d9eSBradley Grove if (!esas2r_init_adapter_struct(a, 41826780d9eSBradley Grove &next_uncached)) { 41926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 42026780d9eSBradley Grove "failed to initialize adapter structure (2)!"); 42126780d9eSBradley Grove esas2r_kill_adapter(index); 42226780d9eSBradley Grove return 0; 42326780d9eSBradley Grove } 42426780d9eSBradley Grove 42526780d9eSBradley Grove tasklet_init(&a->tasklet, 42626780d9eSBradley Grove esas2r_adapter_tasklet, 42726780d9eSBradley Grove (unsigned long)a); 42826780d9eSBradley Grove 42926780d9eSBradley Grove /* 43026780d9eSBradley Grove * Disable chip interrupts to prevent spurious interrupts 43126780d9eSBradley Grove * until we claim the IRQ. 43226780d9eSBradley Grove */ 43326780d9eSBradley Grove esas2r_disable_chip_interrupts(a); 43426780d9eSBradley Grove esas2r_check_adapter(a); 43526780d9eSBradley Grove 43626780d9eSBradley Grove if (!esas2r_init_adapter_hw(a, true)) 43726780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "failed to initialize hardware!"); 43826780d9eSBradley Grove else 43926780d9eSBradley Grove esas2r_debug("esas2r_init_adapter ok"); 44026780d9eSBradley Grove 44126780d9eSBradley Grove esas2r_claim_interrupts(a); 44226780d9eSBradley Grove 4439588d24eSBradley Grove if (test_bit(AF2_IRQ_CLAIMED, &a->flags2)) 44426780d9eSBradley Grove esas2r_enable_chip_interrupts(a); 44526780d9eSBradley Grove 4469588d24eSBradley Grove set_bit(AF2_INIT_DONE, &a->flags2); 4479588d24eSBradley Grove if (!test_bit(AF_DEGRADED_MODE, &a->flags)) 44826780d9eSBradley Grove esas2r_kickoff_timer(a); 44926780d9eSBradley Grove esas2r_debug("esas2r_init_adapter done for %p (%d)", 45026780d9eSBradley Grove a, a->disable_cnt); 45126780d9eSBradley Grove 45226780d9eSBradley Grove return 1; 45326780d9eSBradley Grove } 45426780d9eSBradley Grove 45526780d9eSBradley Grove static void esas2r_adapter_power_down(struct esas2r_adapter *a, 45626780d9eSBradley Grove int power_management) 45726780d9eSBradley Grove { 45826780d9eSBradley Grove struct esas2r_mem_desc *memdesc, *next; 45926780d9eSBradley Grove 4609588d24eSBradley Grove if ((test_bit(AF2_INIT_DONE, &a->flags2)) 4619588d24eSBradley Grove && (!test_bit(AF_DEGRADED_MODE, &a->flags))) { 46226780d9eSBradley Grove if (!power_management) { 46326780d9eSBradley Grove del_timer_sync(&a->timer); 46426780d9eSBradley Grove tasklet_kill(&a->tasklet); 46526780d9eSBradley Grove } 46626780d9eSBradley Grove esas2r_power_down(a); 46726780d9eSBradley Grove 46826780d9eSBradley Grove /* 46926780d9eSBradley Grove * There are versions of firmware that do not handle the sync 47026780d9eSBradley Grove * cache command correctly. Stall here to ensure that the 47126780d9eSBradley Grove * cache is lazily flushed. 47226780d9eSBradley Grove */ 47326780d9eSBradley Grove mdelay(500); 47426780d9eSBradley Grove esas2r_debug("chip halted"); 47526780d9eSBradley Grove } 47626780d9eSBradley Grove 47726780d9eSBradley Grove /* Remove sysfs binary files */ 47826780d9eSBradley Grove if (a->sysfs_fw_created) { 47926780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fw); 48026780d9eSBradley Grove a->sysfs_fw_created = 0; 48126780d9eSBradley Grove } 48226780d9eSBradley Grove 48326780d9eSBradley Grove if (a->sysfs_fs_created) { 48426780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fs); 48526780d9eSBradley Grove a->sysfs_fs_created = 0; 48626780d9eSBradley Grove } 48726780d9eSBradley Grove 48826780d9eSBradley Grove if (a->sysfs_vda_created) { 48926780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_vda); 49026780d9eSBradley Grove a->sysfs_vda_created = 0; 49126780d9eSBradley Grove } 49226780d9eSBradley Grove 49326780d9eSBradley Grove if (a->sysfs_hw_created) { 49426780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_hw); 49526780d9eSBradley Grove a->sysfs_hw_created = 0; 49626780d9eSBradley Grove } 49726780d9eSBradley Grove 49826780d9eSBradley Grove if (a->sysfs_live_nvram_created) { 49926780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, 50026780d9eSBradley Grove &bin_attr_live_nvram); 50126780d9eSBradley Grove a->sysfs_live_nvram_created = 0; 50226780d9eSBradley Grove } 50326780d9eSBradley Grove 50426780d9eSBradley Grove if (a->sysfs_default_nvram_created) { 50526780d9eSBradley Grove sysfs_remove_bin_file(&a->host->shost_dev.kobj, 50626780d9eSBradley Grove &bin_attr_default_nvram); 50726780d9eSBradley Grove a->sysfs_default_nvram_created = 0; 50826780d9eSBradley Grove } 50926780d9eSBradley Grove 51026780d9eSBradley Grove /* Clean up interrupts */ 5119588d24eSBradley Grove if (test_bit(AF2_IRQ_CLAIMED, &a->flags2)) { 51226780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 51326780d9eSBradley Grove &(a->pcid->dev), 51426780d9eSBradley Grove "free_irq(%d) called", a->pcid->irq); 51526780d9eSBradley Grove 51626780d9eSBradley Grove free_irq(a->pcid->irq, a); 51726780d9eSBradley Grove esas2r_debug("IRQ released"); 5189588d24eSBradley Grove clear_bit(AF2_IRQ_CLAIMED, &a->flags2); 51926780d9eSBradley Grove } 52026780d9eSBradley Grove 5219588d24eSBradley Grove if (test_bit(AF2_MSI_ENABLED, &a->flags2)) { 52226780d9eSBradley Grove pci_disable_msi(a->pcid); 5239588d24eSBradley Grove clear_bit(AF2_MSI_ENABLED, &a->flags2); 52426780d9eSBradley Grove esas2r_debug("MSI disabled"); 52526780d9eSBradley Grove } 52626780d9eSBradley Grove 52726780d9eSBradley Grove if (a->inbound_list_md.virt_addr) 52826780d9eSBradley Grove esas2r_initmem_free(a, &a->inbound_list_md); 52926780d9eSBradley Grove 53026780d9eSBradley Grove if (a->outbound_list_md.virt_addr) 53126780d9eSBradley Grove esas2r_initmem_free(a, &a->outbound_list_md); 53226780d9eSBradley Grove 53326780d9eSBradley Grove list_for_each_entry_safe(memdesc, next, &a->free_sg_list_head, 53426780d9eSBradley Grove next_desc) { 53526780d9eSBradley Grove esas2r_initmem_free(a, memdesc); 53626780d9eSBradley Grove } 53726780d9eSBradley Grove 53826780d9eSBradley Grove /* Following frees everything allocated via alloc_vda_req */ 53926780d9eSBradley Grove list_for_each_entry_safe(memdesc, next, &a->vrq_mds_head, next_desc) { 54026780d9eSBradley Grove esas2r_initmem_free(a, memdesc); 54126780d9eSBradley Grove list_del(&memdesc->next_desc); 54226780d9eSBradley Grove kfree(memdesc); 54326780d9eSBradley Grove } 54426780d9eSBradley Grove 54526780d9eSBradley Grove kfree(a->first_ae_req); 54626780d9eSBradley Grove a->first_ae_req = NULL; 54726780d9eSBradley Grove 54826780d9eSBradley Grove kfree(a->sg_list_mds); 54926780d9eSBradley Grove a->sg_list_mds = NULL; 55026780d9eSBradley Grove 55126780d9eSBradley Grove kfree(a->req_table); 55226780d9eSBradley Grove a->req_table = NULL; 55326780d9eSBradley Grove 55426780d9eSBradley Grove if (a->regs) { 55526780d9eSBradley Grove esas2r_unmap_regions(a); 55626780d9eSBradley Grove a->regs = NULL; 55726780d9eSBradley Grove a->data_window = NULL; 55826780d9eSBradley Grove esas2r_debug("regions unmapped"); 55926780d9eSBradley Grove } 56026780d9eSBradley Grove } 56126780d9eSBradley Grove 56226780d9eSBradley Grove /* Release/free allocated resources for specified adapters. */ 56326780d9eSBradley Grove void esas2r_kill_adapter(int i) 56426780d9eSBradley Grove { 56526780d9eSBradley Grove struct esas2r_adapter *a = esas2r_adapters[i]; 56626780d9eSBradley Grove 56726780d9eSBradley Grove if (a) { 56826780d9eSBradley Grove unsigned long flags; 56926780d9eSBradley Grove struct workqueue_struct *wq; 57026780d9eSBradley Grove esas2r_debug("killing adapter %p [%d] ", a, i); 57126780d9eSBradley Grove esas2r_fw_event_off(a); 57226780d9eSBradley Grove esas2r_adapter_power_down(a, 0); 57326780d9eSBradley Grove if (esas2r_buffered_ioctl && 57426780d9eSBradley Grove (a->pcid == esas2r_buffered_ioctl_pcid)) { 57526780d9eSBradley Grove dma_free_coherent(&a->pcid->dev, 57626780d9eSBradley Grove (size_t)esas2r_buffered_ioctl_size, 57726780d9eSBradley Grove esas2r_buffered_ioctl, 57826780d9eSBradley Grove esas2r_buffered_ioctl_addr); 57926780d9eSBradley Grove esas2r_buffered_ioctl = NULL; 58026780d9eSBradley Grove } 58126780d9eSBradley Grove 58226780d9eSBradley Grove if (a->vda_buffer) { 58326780d9eSBradley Grove dma_free_coherent(&a->pcid->dev, 58426780d9eSBradley Grove (size_t)VDA_MAX_BUFFER_SIZE, 58526780d9eSBradley Grove a->vda_buffer, 58626780d9eSBradley Grove (dma_addr_t)a->ppvda_buffer); 58726780d9eSBradley Grove a->vda_buffer = NULL; 58826780d9eSBradley Grove } 58926780d9eSBradley Grove if (a->fs_api_buffer) { 59026780d9eSBradley Grove dma_free_coherent(&a->pcid->dev, 59126780d9eSBradley Grove (size_t)a->fs_api_buffer_size, 59226780d9eSBradley Grove a->fs_api_buffer, 59326780d9eSBradley Grove (dma_addr_t)a->ppfs_api_buffer); 59426780d9eSBradley Grove a->fs_api_buffer = NULL; 59526780d9eSBradley Grove } 59626780d9eSBradley Grove 59726780d9eSBradley Grove kfree(a->local_atto_ioctl); 59826780d9eSBradley Grove a->local_atto_ioctl = NULL; 59926780d9eSBradley Grove 60026780d9eSBradley Grove spin_lock_irqsave(&a->fw_event_lock, flags); 60126780d9eSBradley Grove wq = a->fw_event_q; 60226780d9eSBradley Grove a->fw_event_q = NULL; 60326780d9eSBradley Grove spin_unlock_irqrestore(&a->fw_event_lock, flags); 60426780d9eSBradley Grove if (wq) 60526780d9eSBradley Grove destroy_workqueue(wq); 60626780d9eSBradley Grove 60726780d9eSBradley Grove if (a->uncached) { 60826780d9eSBradley Grove dma_free_coherent(&a->pcid->dev, 60926780d9eSBradley Grove (size_t)a->uncached_size, 61026780d9eSBradley Grove a->uncached, 61126780d9eSBradley Grove (dma_addr_t)a->uncached_phys); 61226780d9eSBradley Grove a->uncached = NULL; 61326780d9eSBradley Grove esas2r_debug("uncached area freed"); 61426780d9eSBradley Grove } 61526780d9eSBradley Grove 61626780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 61726780d9eSBradley Grove &(a->pcid->dev), 61826780d9eSBradley Grove "pci_disable_device() called. msix_enabled: %d " 61926780d9eSBradley Grove "msi_enabled: %d irq: %d pin: %d", 62026780d9eSBradley Grove a->pcid->msix_enabled, 62126780d9eSBradley Grove a->pcid->msi_enabled, 62226780d9eSBradley Grove a->pcid->irq, 62326780d9eSBradley Grove a->pcid->pin); 62426780d9eSBradley Grove 62526780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 62626780d9eSBradley Grove &(a->pcid->dev), 62726780d9eSBradley Grove "before pci_disable_device() enable_cnt: %d", 62826780d9eSBradley Grove a->pcid->enable_cnt.counter); 62926780d9eSBradley Grove 63026780d9eSBradley Grove pci_disable_device(a->pcid); 63126780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 63226780d9eSBradley Grove &(a->pcid->dev), 63326780d9eSBradley Grove "after pci_disable_device() enable_cnt: %d", 63426780d9eSBradley Grove a->pcid->enable_cnt.counter); 63526780d9eSBradley Grove 63626780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 63726780d9eSBradley Grove &(a->pcid->dev), 63826780d9eSBradley Grove "pci_set_drv_data(%p, NULL) called", 63926780d9eSBradley Grove a->pcid); 64026780d9eSBradley Grove 64126780d9eSBradley Grove pci_set_drvdata(a->pcid, NULL); 64226780d9eSBradley Grove esas2r_adapters[i] = NULL; 64326780d9eSBradley Grove 6449588d24eSBradley Grove if (test_bit(AF2_INIT_DONE, &a->flags2)) { 6459588d24eSBradley Grove clear_bit(AF2_INIT_DONE, &a->flags2); 64626780d9eSBradley Grove 6479588d24eSBradley Grove set_bit(AF_DEGRADED_MODE, &a->flags); 64826780d9eSBradley Grove 64926780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 65026780d9eSBradley Grove &(a->host->shost_gendev), 65126780d9eSBradley Grove "scsi_remove_host() called"); 65226780d9eSBradley Grove 65326780d9eSBradley Grove scsi_remove_host(a->host); 65426780d9eSBradley Grove 65526780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, 65626780d9eSBradley Grove &(a->host->shost_gendev), 65726780d9eSBradley Grove "scsi_host_put() called"); 65826780d9eSBradley Grove 65926780d9eSBradley Grove scsi_host_put(a->host); 66026780d9eSBradley Grove } 66126780d9eSBradley Grove } 66226780d9eSBradley Grove } 66326780d9eSBradley Grove 66426780d9eSBradley Grove int esas2r_cleanup(struct Scsi_Host *host) 66526780d9eSBradley Grove { 66664d29bd8SBradley Grove struct esas2r_adapter *a; 66726780d9eSBradley Grove int index; 66826780d9eSBradley Grove 66926780d9eSBradley Grove if (host == NULL) { 67026780d9eSBradley Grove int i; 67126780d9eSBradley Grove 67226780d9eSBradley Grove esas2r_debug("esas2r_cleanup everything"); 67326780d9eSBradley Grove for (i = 0; i < MAX_ADAPTERS; i++) 67426780d9eSBradley Grove esas2r_kill_adapter(i); 67526780d9eSBradley Grove return -1; 67626780d9eSBradley Grove } 67726780d9eSBradley Grove 67826780d9eSBradley Grove esas2r_debug("esas2r_cleanup called for host %p", host); 67964d29bd8SBradley Grove a = (struct esas2r_adapter *)host->hostdata; 68026780d9eSBradley Grove index = a->index; 68126780d9eSBradley Grove esas2r_kill_adapter(index); 68226780d9eSBradley Grove return index; 68326780d9eSBradley Grove } 68426780d9eSBradley Grove 68526780d9eSBradley Grove int esas2r_suspend(struct pci_dev *pdev, pm_message_t state) 68626780d9eSBradley Grove { 68726780d9eSBradley Grove struct Scsi_Host *host = pci_get_drvdata(pdev); 68826780d9eSBradley Grove u32 device_state; 68926780d9eSBradley Grove struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; 69026780d9eSBradley Grove 69126780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "suspending adapter()"); 69226780d9eSBradley Grove if (!a) 69326780d9eSBradley Grove return -ENODEV; 69426780d9eSBradley Grove 69526780d9eSBradley Grove esas2r_adapter_power_down(a, 1); 69626780d9eSBradley Grove device_state = pci_choose_state(pdev, state); 69726780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 69826780d9eSBradley Grove "pci_save_state() called"); 69926780d9eSBradley Grove pci_save_state(pdev); 70026780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 70126780d9eSBradley Grove "pci_disable_device() called"); 70226780d9eSBradley Grove pci_disable_device(pdev); 70326780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 70426780d9eSBradley Grove "pci_set_power_state() called"); 70526780d9eSBradley Grove pci_set_power_state(pdev, device_state); 70626780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_suspend(): 0"); 70726780d9eSBradley Grove return 0; 70826780d9eSBradley Grove } 70926780d9eSBradley Grove 71026780d9eSBradley Grove int esas2r_resume(struct pci_dev *pdev) 71126780d9eSBradley Grove { 71226780d9eSBradley Grove struct Scsi_Host *host = pci_get_drvdata(pdev); 71326780d9eSBradley Grove struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; 71426780d9eSBradley Grove int rez; 71526780d9eSBradley Grove 71626780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "resuming adapter()"); 71726780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 71826780d9eSBradley Grove "pci_set_power_state(PCI_D0) " 71926780d9eSBradley Grove "called"); 72026780d9eSBradley Grove pci_set_power_state(pdev, PCI_D0); 72126780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 72226780d9eSBradley Grove "pci_enable_wake(PCI_D0, 0) " 72326780d9eSBradley Grove "called"); 72426780d9eSBradley Grove pci_enable_wake(pdev, PCI_D0, 0); 72526780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 72626780d9eSBradley Grove "pci_restore_state() called"); 72726780d9eSBradley Grove pci_restore_state(pdev); 72826780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), 72926780d9eSBradley Grove "pci_enable_device() called"); 73026780d9eSBradley Grove rez = pci_enable_device(pdev); 73126780d9eSBradley Grove pci_set_master(pdev); 73226780d9eSBradley Grove 73326780d9eSBradley Grove if (!a) { 73426780d9eSBradley Grove rez = -ENODEV; 73526780d9eSBradley Grove goto error_exit; 73626780d9eSBradley Grove } 73726780d9eSBradley Grove 73826780d9eSBradley Grove if (esas2r_map_regions(a) != 0) { 73926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "could not re-map PCI regions!"); 74026780d9eSBradley Grove rez = -ENOMEM; 74126780d9eSBradley Grove goto error_exit; 74226780d9eSBradley Grove } 74326780d9eSBradley Grove 74426780d9eSBradley Grove /* Set up interupt mode */ 74526780d9eSBradley Grove esas2r_setup_interrupts(a, a->intr_mode); 74626780d9eSBradley Grove 74726780d9eSBradley Grove /* 74826780d9eSBradley Grove * Disable chip interrupts to prevent spurious interrupts until we 74926780d9eSBradley Grove * claim the IRQ. 75026780d9eSBradley Grove */ 75126780d9eSBradley Grove esas2r_disable_chip_interrupts(a); 75226780d9eSBradley Grove if (!esas2r_power_up(a, true)) { 75326780d9eSBradley Grove esas2r_debug("yikes, esas2r_power_up failed"); 75426780d9eSBradley Grove rez = -ENOMEM; 75526780d9eSBradley Grove goto error_exit; 75626780d9eSBradley Grove } 75726780d9eSBradley Grove 75826780d9eSBradley Grove esas2r_claim_interrupts(a); 75926780d9eSBradley Grove 7609588d24eSBradley Grove if (test_bit(AF2_IRQ_CLAIMED, &a->flags2)) { 76126780d9eSBradley Grove /* 76226780d9eSBradley Grove * Now that system interrupt(s) are claimed, we can enable 76326780d9eSBradley Grove * chip interrupts. 76426780d9eSBradley Grove */ 76526780d9eSBradley Grove esas2r_enable_chip_interrupts(a); 76626780d9eSBradley Grove esas2r_kickoff_timer(a); 76726780d9eSBradley Grove } else { 76826780d9eSBradley Grove esas2r_debug("yikes, unable to claim IRQ"); 76926780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "could not re-claim IRQ!"); 77026780d9eSBradley Grove rez = -ENOMEM; 77126780d9eSBradley Grove goto error_exit; 77226780d9eSBradley Grove } 77326780d9eSBradley Grove 77426780d9eSBradley Grove error_exit: 77526780d9eSBradley Grove esas2r_log_dev(ESAS2R_LOG_CRIT, &(pdev->dev), "esas2r_resume(): %d", 77626780d9eSBradley Grove rez); 77726780d9eSBradley Grove return rez; 77826780d9eSBradley Grove } 77926780d9eSBradley Grove 78026780d9eSBradley Grove bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str) 78126780d9eSBradley Grove { 7829588d24eSBradley Grove set_bit(AF_DEGRADED_MODE, &a->flags); 78326780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 78426780d9eSBradley Grove "setting adapter to degraded mode: %s\n", error_str); 78526780d9eSBradley Grove return false; 78626780d9eSBradley Grove } 78726780d9eSBradley Grove 78826780d9eSBradley Grove u32 esas2r_get_uncached_size(struct esas2r_adapter *a) 78926780d9eSBradley Grove { 79026780d9eSBradley Grove return sizeof(struct esas2r_sas_nvram) 79126780d9eSBradley Grove + ALIGN(ESAS2R_DISC_BUF_LEN, 8) 79226780d9eSBradley Grove + ALIGN(sizeof(u32), 8) /* outbound list copy pointer */ 79326780d9eSBradley Grove + 8 79426780d9eSBradley Grove + (num_sg_lists * (u16)sgl_page_size) 79526780d9eSBradley Grove + ALIGN((num_requests + num_ae_requests + 1 + 79626780d9eSBradley Grove ESAS2R_LIST_EXTRA) * 79726780d9eSBradley Grove sizeof(struct esas2r_inbound_list_source_entry), 79826780d9eSBradley Grove 8) 79926780d9eSBradley Grove + ALIGN((num_requests + num_ae_requests + 1 + 80026780d9eSBradley Grove ESAS2R_LIST_EXTRA) * 80126780d9eSBradley Grove sizeof(struct atto_vda_ob_rsp), 8) 80226780d9eSBradley Grove + 256; /* VDA request and buffer align */ 80326780d9eSBradley Grove } 80426780d9eSBradley Grove 80526780d9eSBradley Grove static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a) 80626780d9eSBradley Grove { 80726780d9eSBradley Grove int pcie_cap_reg; 80826780d9eSBradley Grove 80926780d9eSBradley Grove pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP); 810b1cf7a2bSBradley Grove if (pcie_cap_reg) { 81126780d9eSBradley Grove u16 devcontrol; 81226780d9eSBradley Grove 81326780d9eSBradley Grove pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL, 81426780d9eSBradley Grove &devcontrol); 81526780d9eSBradley Grove 81688b71f9cSRafał Miłecki if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > 81788b71f9cSRafał Miłecki PCI_EXP_DEVCTL_READRQ_512B) { 81826780d9eSBradley Grove esas2r_log(ESAS2R_LOG_INFO, 81926780d9eSBradley Grove "max read request size > 512B"); 82026780d9eSBradley Grove 82126780d9eSBradley Grove devcontrol &= ~PCI_EXP_DEVCTL_READRQ; 82288b71f9cSRafał Miłecki devcontrol |= PCI_EXP_DEVCTL_READRQ_512B; 82326780d9eSBradley Grove pci_write_config_word(a->pcid, 82426780d9eSBradley Grove pcie_cap_reg + PCI_EXP_DEVCTL, 82526780d9eSBradley Grove devcontrol); 82626780d9eSBradley Grove } 82726780d9eSBradley Grove } 82826780d9eSBradley Grove } 82926780d9eSBradley Grove 83026780d9eSBradley Grove /* 83126780d9eSBradley Grove * Determine the organization of the uncached data area and 83226780d9eSBradley Grove * finish initializing the adapter structure 83326780d9eSBradley Grove */ 83426780d9eSBradley Grove bool esas2r_init_adapter_struct(struct esas2r_adapter *a, 83526780d9eSBradley Grove void **uncached_area) 83626780d9eSBradley Grove { 83726780d9eSBradley Grove u32 i; 83826780d9eSBradley Grove u8 *high; 83926780d9eSBradley Grove struct esas2r_inbound_list_source_entry *element; 84026780d9eSBradley Grove struct esas2r_request *rq; 84126780d9eSBradley Grove struct esas2r_mem_desc *sgl; 84226780d9eSBradley Grove 84326780d9eSBradley Grove spin_lock_init(&a->sg_list_lock); 84426780d9eSBradley Grove spin_lock_init(&a->mem_lock); 84526780d9eSBradley Grove spin_lock_init(&a->queue_lock); 84626780d9eSBradley Grove 84726780d9eSBradley Grove a->targetdb_end = &a->targetdb[ESAS2R_MAX_TARGETS]; 84826780d9eSBradley Grove 84926780d9eSBradley Grove if (!alloc_vda_req(a, &a->general_req)) { 85026780d9eSBradley Grove esas2r_hdebug( 85126780d9eSBradley Grove "failed to allocate a VDA request for the general req!"); 85226780d9eSBradley Grove return false; 85326780d9eSBradley Grove } 85426780d9eSBradley Grove 85526780d9eSBradley Grove /* allocate requests for asynchronous events */ 85626780d9eSBradley Grove a->first_ae_req = 85726780d9eSBradley Grove kzalloc(num_ae_requests * sizeof(struct esas2r_request), 85826780d9eSBradley Grove GFP_KERNEL); 85926780d9eSBradley Grove 86026780d9eSBradley Grove if (a->first_ae_req == NULL) { 86126780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 86226780d9eSBradley Grove "failed to allocate memory for asynchronous events"); 86326780d9eSBradley Grove return false; 86426780d9eSBradley Grove } 86526780d9eSBradley Grove 86626780d9eSBradley Grove /* allocate the S/G list memory descriptors */ 86726780d9eSBradley Grove a->sg_list_mds = kzalloc( 86826780d9eSBradley Grove num_sg_lists * sizeof(struct esas2r_mem_desc), GFP_KERNEL); 86926780d9eSBradley Grove 87026780d9eSBradley Grove if (a->sg_list_mds == NULL) { 87126780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 87226780d9eSBradley Grove "failed to allocate memory for s/g list descriptors"); 87326780d9eSBradley Grove return false; 87426780d9eSBradley Grove } 87526780d9eSBradley Grove 87626780d9eSBradley Grove /* allocate the request table */ 87726780d9eSBradley Grove a->req_table = 87826780d9eSBradley Grove kzalloc((num_requests + num_ae_requests + 87926780d9eSBradley Grove 1) * sizeof(struct esas2r_request *), GFP_KERNEL); 88026780d9eSBradley Grove 88126780d9eSBradley Grove if (a->req_table == NULL) { 88226780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, 88326780d9eSBradley Grove "failed to allocate memory for the request table"); 88426780d9eSBradley Grove return false; 88526780d9eSBradley Grove } 88626780d9eSBradley Grove 88726780d9eSBradley Grove /* initialize PCI configuration space */ 88826780d9eSBradley Grove esas2r_init_pci_cfg_space(a); 88926780d9eSBradley Grove 89026780d9eSBradley Grove /* 89126780d9eSBradley Grove * the thunder_stream boards all have a serial flash part that has a 89226780d9eSBradley Grove * different base address on the AHB bus. 89326780d9eSBradley Grove */ 89426780d9eSBradley Grove if ((a->pcid->subsystem_vendor == ATTO_VENDOR_ID) 89526780d9eSBradley Grove && (a->pcid->subsystem_device & ATTO_SSDID_TBT)) 89626780d9eSBradley Grove a->flags2 |= AF2_THUNDERBOLT; 89726780d9eSBradley Grove 8989588d24eSBradley Grove if (test_bit(AF2_THUNDERBOLT, &a->flags2)) 89926780d9eSBradley Grove a->flags2 |= AF2_SERIAL_FLASH; 90026780d9eSBradley Grove 90126780d9eSBradley Grove if (a->pcid->subsystem_device == ATTO_TLSH_1068) 90226780d9eSBradley Grove a->flags2 |= AF2_THUNDERLINK; 90326780d9eSBradley Grove 90426780d9eSBradley Grove /* Uncached Area */ 90526780d9eSBradley Grove high = (u8 *)*uncached_area; 90626780d9eSBradley Grove 90726780d9eSBradley Grove /* initialize the scatter/gather table pages */ 90826780d9eSBradley Grove 90926780d9eSBradley Grove for (i = 0, sgl = a->sg_list_mds; i < num_sg_lists; i++, sgl++) { 91026780d9eSBradley Grove sgl->size = sgl_page_size; 91126780d9eSBradley Grove 91226780d9eSBradley Grove list_add_tail(&sgl->next_desc, &a->free_sg_list_head); 91326780d9eSBradley Grove 91426780d9eSBradley Grove if (!esas2r_initmem_alloc(a, sgl, ESAS2R_SGL_ALIGN)) { 91526780d9eSBradley Grove /* Allow the driver to load if the minimum count met. */ 91626780d9eSBradley Grove if (i < NUM_SGL_MIN) 91726780d9eSBradley Grove return false; 91826780d9eSBradley Grove break; 91926780d9eSBradley Grove } 92026780d9eSBradley Grove } 92126780d9eSBradley Grove 92226780d9eSBradley Grove /* compute the size of the lists */ 92326780d9eSBradley Grove a->list_size = num_requests + ESAS2R_LIST_EXTRA; 92426780d9eSBradley Grove 92526780d9eSBradley Grove /* allocate the inbound list */ 92626780d9eSBradley Grove a->inbound_list_md.size = a->list_size * 92726780d9eSBradley Grove sizeof(struct 92826780d9eSBradley Grove esas2r_inbound_list_source_entry); 92926780d9eSBradley Grove 93026780d9eSBradley Grove if (!esas2r_initmem_alloc(a, &a->inbound_list_md, ESAS2R_LIST_ALIGN)) { 93126780d9eSBradley Grove esas2r_hdebug("failed to allocate IB list"); 93226780d9eSBradley Grove return false; 93326780d9eSBradley Grove } 93426780d9eSBradley Grove 93526780d9eSBradley Grove /* allocate the outbound list */ 93626780d9eSBradley Grove a->outbound_list_md.size = a->list_size * 93726780d9eSBradley Grove sizeof(struct atto_vda_ob_rsp); 93826780d9eSBradley Grove 93926780d9eSBradley Grove if (!esas2r_initmem_alloc(a, &a->outbound_list_md, 94026780d9eSBradley Grove ESAS2R_LIST_ALIGN)) { 94126780d9eSBradley Grove esas2r_hdebug("failed to allocate IB list"); 94226780d9eSBradley Grove return false; 94326780d9eSBradley Grove } 94426780d9eSBradley Grove 94526780d9eSBradley Grove /* allocate the NVRAM structure */ 94626780d9eSBradley Grove a->nvram = (struct esas2r_sas_nvram *)high; 94726780d9eSBradley Grove high += sizeof(struct esas2r_sas_nvram); 94826780d9eSBradley Grove 94926780d9eSBradley Grove /* allocate the discovery buffer */ 95026780d9eSBradley Grove a->disc_buffer = high; 95126780d9eSBradley Grove high += ESAS2R_DISC_BUF_LEN; 95226780d9eSBradley Grove high = PTR_ALIGN(high, 8); 95326780d9eSBradley Grove 95426780d9eSBradley Grove /* allocate the outbound list copy pointer */ 95526780d9eSBradley Grove a->outbound_copy = (u32 volatile *)high; 95626780d9eSBradley Grove high += sizeof(u32); 95726780d9eSBradley Grove 9589588d24eSBradley Grove if (!test_bit(AF_NVR_VALID, &a->flags)) 95926780d9eSBradley Grove esas2r_nvram_set_defaults(a); 96026780d9eSBradley Grove 96126780d9eSBradley Grove /* update the caller's uncached memory area pointer */ 96226780d9eSBradley Grove *uncached_area = (void *)high; 96326780d9eSBradley Grove 96426780d9eSBradley Grove /* initialize the allocated memory */ 9659588d24eSBradley Grove if (test_bit(AF_FIRST_INIT, &a->flags)) { 96626780d9eSBradley Grove memset(a->req_table, 0, 96726780d9eSBradley Grove (num_requests + num_ae_requests + 96826780d9eSBradley Grove 1) * sizeof(struct esas2r_request *)); 96926780d9eSBradley Grove 97026780d9eSBradley Grove esas2r_targ_db_initialize(a); 97126780d9eSBradley Grove 97226780d9eSBradley Grove /* prime parts of the inbound list */ 97326780d9eSBradley Grove element = 97426780d9eSBradley Grove (struct esas2r_inbound_list_source_entry *)a-> 97526780d9eSBradley Grove inbound_list_md. 97626780d9eSBradley Grove virt_addr; 97726780d9eSBradley Grove 97826780d9eSBradley Grove for (i = 0; i < a->list_size; i++) { 97926780d9eSBradley Grove element->address = 0; 98026780d9eSBradley Grove element->reserved = 0; 98126780d9eSBradley Grove element->length = cpu_to_le32(HWILSE_INTERFACE_F0 98226780d9eSBradley Grove | (sizeof(union 98326780d9eSBradley Grove atto_vda_req) 98426780d9eSBradley Grove / 98526780d9eSBradley Grove sizeof(u32))); 98626780d9eSBradley Grove element++; 98726780d9eSBradley Grove } 98826780d9eSBradley Grove 98926780d9eSBradley Grove /* init the AE requests */ 99026780d9eSBradley Grove for (rq = a->first_ae_req, i = 0; i < num_ae_requests; rq++, 99126780d9eSBradley Grove i++) { 99226780d9eSBradley Grove INIT_LIST_HEAD(&rq->req_list); 99326780d9eSBradley Grove if (!alloc_vda_req(a, rq)) { 99426780d9eSBradley Grove esas2r_hdebug( 99526780d9eSBradley Grove "failed to allocate a VDA request!"); 99626780d9eSBradley Grove return false; 99726780d9eSBradley Grove } 99826780d9eSBradley Grove 99926780d9eSBradley Grove esas2r_rq_init_request(rq, a); 100026780d9eSBradley Grove 100126780d9eSBradley Grove /* override the completion function */ 100226780d9eSBradley Grove rq->comp_cb = esas2r_ae_complete; 100326780d9eSBradley Grove } 100426780d9eSBradley Grove } 100526780d9eSBradley Grove 100626780d9eSBradley Grove return true; 100726780d9eSBradley Grove } 100826780d9eSBradley Grove 100926780d9eSBradley Grove /* This code will verify that the chip is operational. */ 101026780d9eSBradley Grove bool esas2r_check_adapter(struct esas2r_adapter *a) 101126780d9eSBradley Grove { 101226780d9eSBradley Grove u32 starttime; 101326780d9eSBradley Grove u32 doorbell; 101426780d9eSBradley Grove u64 ppaddr; 101526780d9eSBradley Grove u32 dw; 101626780d9eSBradley Grove 101726780d9eSBradley Grove /* 101826780d9eSBradley Grove * if the chip reset detected flag is set, we can bypass a bunch of 101926780d9eSBradley Grove * stuff. 102026780d9eSBradley Grove */ 10219588d24eSBradley Grove if (test_bit(AF_CHPRST_DETECTED, &a->flags)) 102226780d9eSBradley Grove goto skip_chip_reset; 102326780d9eSBradley Grove 102426780d9eSBradley Grove /* 102526780d9eSBradley Grove * BEFORE WE DO ANYTHING, disable the chip interrupts! the boot driver 102626780d9eSBradley Grove * may have left them enabled or we may be recovering from a fault. 102726780d9eSBradley Grove */ 102826780d9eSBradley Grove esas2r_write_register_dword(a, MU_INT_MASK_OUT, ESAS2R_INT_DIS_MASK); 102926780d9eSBradley Grove esas2r_flush_register_dword(a, MU_INT_MASK_OUT); 103026780d9eSBradley Grove 103126780d9eSBradley Grove /* 103226780d9eSBradley Grove * wait for the firmware to become ready by forcing an interrupt and 103326780d9eSBradley Grove * waiting for a response. 103426780d9eSBradley Grove */ 103526780d9eSBradley Grove starttime = jiffies_to_msecs(jiffies); 103626780d9eSBradley Grove 103726780d9eSBradley Grove while (true) { 103826780d9eSBradley Grove esas2r_force_interrupt(a); 103926780d9eSBradley Grove doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT); 104026780d9eSBradley Grove if (doorbell == 0xFFFFFFFF) { 104126780d9eSBradley Grove /* 104226780d9eSBradley Grove * Give the firmware up to two seconds to enable 104326780d9eSBradley Grove * register access after a reset. 104426780d9eSBradley Grove */ 104526780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 2000) 104626780d9eSBradley Grove return esas2r_set_degraded_mode(a, 104726780d9eSBradley Grove "unable to access registers"); 104826780d9eSBradley Grove } else if (doorbell & DRBL_FORCE_INT) { 104926780d9eSBradley Grove u32 ver = (doorbell & DRBL_FW_VER_MSK); 105026780d9eSBradley Grove 105126780d9eSBradley Grove /* 105226780d9eSBradley Grove * This driver supports version 0 and version 1 of 105326780d9eSBradley Grove * the API 105426780d9eSBradley Grove */ 105526780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT, 105626780d9eSBradley Grove doorbell); 105726780d9eSBradley Grove 105826780d9eSBradley Grove if (ver == DRBL_FW_VER_0) { 10599588d24eSBradley Grove set_bit(AF_LEGACY_SGE_MODE, &a->flags); 106026780d9eSBradley Grove 106126780d9eSBradley Grove a->max_vdareq_size = 128; 106226780d9eSBradley Grove a->build_sgl = esas2r_build_sg_list_sge; 106326780d9eSBradley Grove } else if (ver == DRBL_FW_VER_1) { 10649588d24eSBradley Grove clear_bit(AF_LEGACY_SGE_MODE, &a->flags); 106526780d9eSBradley Grove 106626780d9eSBradley Grove a->max_vdareq_size = 1024; 106726780d9eSBradley Grove a->build_sgl = esas2r_build_sg_list_prd; 106826780d9eSBradley Grove } else { 106926780d9eSBradley Grove return esas2r_set_degraded_mode(a, 107026780d9eSBradley Grove "unknown firmware version"); 107126780d9eSBradley Grove } 107226780d9eSBradley Grove break; 107326780d9eSBradley Grove } 107426780d9eSBradley Grove 107526780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(100)); 107626780d9eSBradley Grove 107726780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 180000) { 107826780d9eSBradley Grove esas2r_hdebug("FW ready TMO"); 107926780d9eSBradley Grove esas2r_bugon(); 108026780d9eSBradley Grove 108126780d9eSBradley Grove return esas2r_set_degraded_mode(a, 108226780d9eSBradley Grove "firmware start has timed out"); 108326780d9eSBradley Grove } 108426780d9eSBradley Grove } 108526780d9eSBradley Grove 108626780d9eSBradley Grove /* purge any asynchronous events since we will repost them later */ 108726780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_DOWN); 108826780d9eSBradley Grove starttime = jiffies_to_msecs(jiffies); 108926780d9eSBradley Grove 109026780d9eSBradley Grove while (true) { 109126780d9eSBradley Grove doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT); 109226780d9eSBradley Grove if (doorbell & DRBL_MSG_IFC_DOWN) { 109326780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT, 109426780d9eSBradley Grove doorbell); 109526780d9eSBradley Grove break; 109626780d9eSBradley Grove } 109726780d9eSBradley Grove 109826780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(50)); 109926780d9eSBradley Grove 110026780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 3000) { 110126780d9eSBradley Grove esas2r_hdebug("timeout waiting for interface down"); 110226780d9eSBradley Grove break; 110326780d9eSBradley Grove } 110426780d9eSBradley Grove } 110526780d9eSBradley Grove skip_chip_reset: 110626780d9eSBradley Grove /* 110726780d9eSBradley Grove * first things first, before we go changing any of these registers 110826780d9eSBradley Grove * disable the communication lists. 110926780d9eSBradley Grove */ 111026780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG); 111126780d9eSBradley Grove dw &= ~MU_ILC_ENABLE; 111226780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw); 111326780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG); 111426780d9eSBradley Grove dw &= ~MU_OLC_ENABLE; 111526780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw); 111626780d9eSBradley Grove 111726780d9eSBradley Grove /* configure the communication list addresses */ 111826780d9eSBradley Grove ppaddr = a->inbound_list_md.phys_addr; 111926780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_ADDR_LO, 112026780d9eSBradley Grove lower_32_bits(ppaddr)); 112126780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_ADDR_HI, 112226780d9eSBradley Grove upper_32_bits(ppaddr)); 112326780d9eSBradley Grove ppaddr = a->outbound_list_md.phys_addr; 112426780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_LO, 112526780d9eSBradley Grove lower_32_bits(ppaddr)); 112626780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_HI, 112726780d9eSBradley Grove upper_32_bits(ppaddr)); 112826780d9eSBradley Grove ppaddr = a->uncached_phys + 112926780d9eSBradley Grove ((u8 *)a->outbound_copy - a->uncached); 113026780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_LO, 113126780d9eSBradley Grove lower_32_bits(ppaddr)); 113226780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_HI, 113326780d9eSBradley Grove upper_32_bits(ppaddr)); 113426780d9eSBradley Grove 113526780d9eSBradley Grove /* reset the read and write pointers */ 113626780d9eSBradley Grove *a->outbound_copy = 113726780d9eSBradley Grove a->last_write = 113826780d9eSBradley Grove a->last_read = a->list_size - 1; 11399588d24eSBradley Grove set_bit(AF_COMM_LIST_TOGGLE, &a->flags); 114026780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_WRITE, MU_ILW_TOGGLE | 114126780d9eSBradley Grove a->last_write); 114226780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_COPY, MU_OLC_TOGGLE | 114326780d9eSBradley Grove a->last_write); 114426780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_READ, MU_ILR_TOGGLE | 114526780d9eSBradley Grove a->last_write); 114626780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_WRITE, 114726780d9eSBradley Grove MU_OLW_TOGGLE | a->last_write); 114826780d9eSBradley Grove 114926780d9eSBradley Grove /* configure the interface select fields */ 115026780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_IN_LIST_IFC_CONFIG); 115126780d9eSBradley Grove dw &= ~(MU_ILIC_LIST | MU_ILIC_DEST); 115226780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_IFC_CONFIG, 115326780d9eSBradley Grove (dw | MU_ILIC_LIST_F0 | MU_ILIC_DEST_DDR)); 115426780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_OUT_LIST_IFC_CONFIG); 115526780d9eSBradley Grove dw &= ~(MU_OLIC_LIST | MU_OLIC_SOURCE); 115626780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_IFC_CONFIG, 115726780d9eSBradley Grove (dw | MU_OLIC_LIST_F0 | 115826780d9eSBradley Grove MU_OLIC_SOURCE_DDR)); 115926780d9eSBradley Grove 116026780d9eSBradley Grove /* finish configuring the communication lists */ 116126780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG); 116226780d9eSBradley Grove dw &= ~(MU_ILC_ENTRY_MASK | MU_ILC_NUMBER_MASK); 116326780d9eSBradley Grove dw |= MU_ILC_ENTRY_4_DW | MU_ILC_DYNAMIC_SRC 116426780d9eSBradley Grove | (a->list_size << MU_ILC_NUMBER_SHIFT); 116526780d9eSBradley Grove esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw); 116626780d9eSBradley Grove dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG); 116726780d9eSBradley Grove dw &= ~(MU_OLC_ENTRY_MASK | MU_OLC_NUMBER_MASK); 116826780d9eSBradley Grove dw |= MU_OLC_ENTRY_4_DW | (a->list_size << MU_OLC_NUMBER_SHIFT); 116926780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw); 117026780d9eSBradley Grove 117126780d9eSBradley Grove /* 117226780d9eSBradley Grove * notify the firmware that we're done setting up the communication 117326780d9eSBradley Grove * list registers. wait here until the firmware is done configuring 117426780d9eSBradley Grove * its lists. it will signal that it is done by enabling the lists. 117526780d9eSBradley Grove */ 117626780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_INIT); 117726780d9eSBradley Grove starttime = jiffies_to_msecs(jiffies); 117826780d9eSBradley Grove 117926780d9eSBradley Grove while (true) { 118026780d9eSBradley Grove doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT); 118126780d9eSBradley Grove if (doorbell & DRBL_MSG_IFC_INIT) { 118226780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT, 118326780d9eSBradley Grove doorbell); 118426780d9eSBradley Grove break; 118526780d9eSBradley Grove } 118626780d9eSBradley Grove 118726780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(100)); 118826780d9eSBradley Grove 118926780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 3000) { 119026780d9eSBradley Grove esas2r_hdebug( 119126780d9eSBradley Grove "timeout waiting for communication list init"); 119226780d9eSBradley Grove esas2r_bugon(); 119326780d9eSBradley Grove return esas2r_set_degraded_mode(a, 119426780d9eSBradley Grove "timeout waiting for communication list init"); 119526780d9eSBradley Grove } 119626780d9eSBradley Grove } 119726780d9eSBradley Grove 119826780d9eSBradley Grove /* 119926780d9eSBradley Grove * flag whether the firmware supports the power down doorbell. we 120026780d9eSBradley Grove * determine this by reading the inbound doorbell enable mask. 120126780d9eSBradley Grove */ 120226780d9eSBradley Grove doorbell = esas2r_read_register_dword(a, MU_DOORBELL_IN_ENB); 120326780d9eSBradley Grove if (doorbell & DRBL_POWER_DOWN) 12049588d24eSBradley Grove set_bit(AF2_VDA_POWER_DOWN, &a->flags2); 120526780d9eSBradley Grove else 12069588d24eSBradley Grove clear_bit(AF2_VDA_POWER_DOWN, &a->flags2); 120726780d9eSBradley Grove 120826780d9eSBradley Grove /* 120926780d9eSBradley Grove * enable assertion of outbound queue and doorbell interrupts in the 121026780d9eSBradley Grove * main interrupt cause register. 121126780d9eSBradley Grove */ 121226780d9eSBradley Grove esas2r_write_register_dword(a, MU_OUT_LIST_INT_MASK, MU_OLIS_MASK); 121326780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT_ENB, DRBL_ENB_MASK); 121426780d9eSBradley Grove return true; 121526780d9eSBradley Grove } 121626780d9eSBradley Grove 121726780d9eSBradley Grove /* Process the initialization message just completed and format the next one. */ 121826780d9eSBradley Grove static bool esas2r_format_init_msg(struct esas2r_adapter *a, 121926780d9eSBradley Grove struct esas2r_request *rq) 122026780d9eSBradley Grove { 122126780d9eSBradley Grove u32 msg = a->init_msg; 122226780d9eSBradley Grove struct atto_vda_cfg_init *ci; 122326780d9eSBradley Grove 122426780d9eSBradley Grove a->init_msg = 0; 122526780d9eSBradley Grove 122626780d9eSBradley Grove switch (msg) { 122726780d9eSBradley Grove case ESAS2R_INIT_MSG_START: 122826780d9eSBradley Grove case ESAS2R_INIT_MSG_REINIT: 122926780d9eSBradley Grove { 123026780d9eSBradley Grove struct timeval now; 123126780d9eSBradley Grove do_gettimeofday(&now); 123226780d9eSBradley Grove esas2r_hdebug("CFG init"); 123326780d9eSBradley Grove esas2r_build_cfg_req(a, 123426780d9eSBradley Grove rq, 123526780d9eSBradley Grove VDA_CFG_INIT, 123626780d9eSBradley Grove 0, 123726780d9eSBradley Grove NULL); 123826780d9eSBradley Grove ci = (struct atto_vda_cfg_init *)&rq->vrq->cfg.data.init; 12398e65e2f0SBradley Grove ci->sgl_page_size = cpu_to_le32(sgl_page_size); 12408e65e2f0SBradley Grove ci->epoch_time = cpu_to_le32(now.tv_sec); 124126780d9eSBradley Grove rq->flags |= RF_FAILURE_OK; 124226780d9eSBradley Grove a->init_msg = ESAS2R_INIT_MSG_INIT; 124326780d9eSBradley Grove break; 124426780d9eSBradley Grove } 124526780d9eSBradley Grove 124626780d9eSBradley Grove case ESAS2R_INIT_MSG_INIT: 124726780d9eSBradley Grove if (rq->req_stat == RS_SUCCESS) { 124826780d9eSBradley Grove u32 major; 124926780d9eSBradley Grove u32 minor; 12508e65e2f0SBradley Grove u16 fw_release; 125126780d9eSBradley Grove 125226780d9eSBradley Grove a->fw_version = le16_to_cpu( 125326780d9eSBradley Grove rq->func_rsp.cfg_rsp.vda_version); 125426780d9eSBradley Grove a->fw_build = rq->func_rsp.cfg_rsp.fw_build; 12558e65e2f0SBradley Grove fw_release = le16_to_cpu( 12568e65e2f0SBradley Grove rq->func_rsp.cfg_rsp.fw_release); 12578e65e2f0SBradley Grove major = LOBYTE(fw_release); 12588e65e2f0SBradley Grove minor = HIBYTE(fw_release); 125926780d9eSBradley Grove a->fw_version += (major << 16) + (minor << 24); 126026780d9eSBradley Grove } else { 126126780d9eSBradley Grove esas2r_hdebug("FAILED"); 126226780d9eSBradley Grove } 126326780d9eSBradley Grove 126426780d9eSBradley Grove /* 126526780d9eSBradley Grove * the 2.71 and earlier releases of R6xx firmware did not error 126626780d9eSBradley Grove * unsupported config requests correctly. 126726780d9eSBradley Grove */ 126826780d9eSBradley Grove 12699588d24eSBradley Grove if ((test_bit(AF2_THUNDERBOLT, &a->flags2)) 12709588d24eSBradley Grove || (be32_to_cpu(a->fw_version) > 0x00524702)) { 127126780d9eSBradley Grove esas2r_hdebug("CFG get init"); 127226780d9eSBradley Grove esas2r_build_cfg_req(a, 127326780d9eSBradley Grove rq, 127426780d9eSBradley Grove VDA_CFG_GET_INIT2, 127526780d9eSBradley Grove sizeof(struct atto_vda_cfg_init), 127626780d9eSBradley Grove NULL); 127726780d9eSBradley Grove 127826780d9eSBradley Grove rq->vrq->cfg.sg_list_offset = offsetof( 127926780d9eSBradley Grove struct atto_vda_cfg_req, 128026780d9eSBradley Grove data.sge); 128126780d9eSBradley Grove rq->vrq->cfg.data.prde.ctl_len = 128226780d9eSBradley Grove cpu_to_le32(sizeof(struct atto_vda_cfg_init)); 128326780d9eSBradley Grove rq->vrq->cfg.data.prde.address = cpu_to_le64( 128426780d9eSBradley Grove rq->vrq_md->phys_addr + 128526780d9eSBradley Grove sizeof(union atto_vda_req)); 128626780d9eSBradley Grove rq->flags |= RF_FAILURE_OK; 128726780d9eSBradley Grove a->init_msg = ESAS2R_INIT_MSG_GET_INIT; 128826780d9eSBradley Grove break; 128926780d9eSBradley Grove } 129026780d9eSBradley Grove 129126780d9eSBradley Grove case ESAS2R_INIT_MSG_GET_INIT: 129226780d9eSBradley Grove if (msg == ESAS2R_INIT_MSG_GET_INIT) { 129326780d9eSBradley Grove ci = (struct atto_vda_cfg_init *)rq->data_buf; 129426780d9eSBradley Grove if (rq->req_stat == RS_SUCCESS) { 129526780d9eSBradley Grove a->num_targets_backend = 129626780d9eSBradley Grove le32_to_cpu(ci->num_targets_backend); 129726780d9eSBradley Grove a->ioctl_tunnel = 129826780d9eSBradley Grove le32_to_cpu(ci->ioctl_tunnel); 129926780d9eSBradley Grove } else { 130026780d9eSBradley Grove esas2r_hdebug("FAILED"); 130126780d9eSBradley Grove } 130226780d9eSBradley Grove } 130326780d9eSBradley Grove /* fall through */ 130426780d9eSBradley Grove 130526780d9eSBradley Grove default: 130626780d9eSBradley Grove rq->req_stat = RS_SUCCESS; 130726780d9eSBradley Grove return false; 130826780d9eSBradley Grove } 130926780d9eSBradley Grove return true; 131026780d9eSBradley Grove } 131126780d9eSBradley Grove 131226780d9eSBradley Grove /* 131326780d9eSBradley Grove * Perform initialization messages via the request queue. Messages are 131426780d9eSBradley Grove * performed with interrupts disabled. 131526780d9eSBradley Grove */ 131626780d9eSBradley Grove bool esas2r_init_msgs(struct esas2r_adapter *a) 131726780d9eSBradley Grove { 131826780d9eSBradley Grove bool success = true; 131926780d9eSBradley Grove struct esas2r_request *rq = &a->general_req; 132026780d9eSBradley Grove 132126780d9eSBradley Grove esas2r_rq_init_request(rq, a); 132226780d9eSBradley Grove rq->comp_cb = esas2r_dummy_complete; 132326780d9eSBradley Grove 132426780d9eSBradley Grove if (a->init_msg == 0) 132526780d9eSBradley Grove a->init_msg = ESAS2R_INIT_MSG_REINIT; 132626780d9eSBradley Grove 132726780d9eSBradley Grove while (a->init_msg) { 132826780d9eSBradley Grove if (esas2r_format_init_msg(a, rq)) { 132926780d9eSBradley Grove unsigned long flags; 133026780d9eSBradley Grove while (true) { 133126780d9eSBradley Grove spin_lock_irqsave(&a->queue_lock, flags); 133226780d9eSBradley Grove esas2r_start_vda_request(a, rq); 133326780d9eSBradley Grove spin_unlock_irqrestore(&a->queue_lock, flags); 133426780d9eSBradley Grove esas2r_wait_request(a, rq); 133526780d9eSBradley Grove if (rq->req_stat != RS_PENDING) 133626780d9eSBradley Grove break; 133726780d9eSBradley Grove } 133826780d9eSBradley Grove } 133926780d9eSBradley Grove 134026780d9eSBradley Grove if (rq->req_stat == RS_SUCCESS 134126780d9eSBradley Grove || ((rq->flags & RF_FAILURE_OK) 134226780d9eSBradley Grove && rq->req_stat != RS_TIMEOUT)) 134326780d9eSBradley Grove continue; 134426780d9eSBradley Grove 134526780d9eSBradley Grove esas2r_log(ESAS2R_LOG_CRIT, "init message %x failed (%x, %x)", 134626780d9eSBradley Grove a->init_msg, rq->req_stat, rq->flags); 134726780d9eSBradley Grove a->init_msg = ESAS2R_INIT_MSG_START; 134826780d9eSBradley Grove success = false; 134926780d9eSBradley Grove break; 135026780d9eSBradley Grove } 135126780d9eSBradley Grove 135226780d9eSBradley Grove esas2r_rq_destroy_request(rq, a); 135326780d9eSBradley Grove return success; 135426780d9eSBradley Grove } 135526780d9eSBradley Grove 135626780d9eSBradley Grove /* Initialize the adapter chip */ 135726780d9eSBradley Grove bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll) 135826780d9eSBradley Grove { 135926780d9eSBradley Grove bool rslt = false; 136026780d9eSBradley Grove struct esas2r_request *rq; 136126780d9eSBradley Grove u32 i; 136226780d9eSBradley Grove 13639588d24eSBradley Grove if (test_bit(AF_DEGRADED_MODE, &a->flags)) 136426780d9eSBradley Grove goto exit; 136526780d9eSBradley Grove 13669588d24eSBradley Grove if (!test_bit(AF_NVR_VALID, &a->flags)) { 136726780d9eSBradley Grove if (!esas2r_nvram_read_direct(a)) 136826780d9eSBradley Grove esas2r_log(ESAS2R_LOG_WARN, 136926780d9eSBradley Grove "invalid/missing NVRAM parameters"); 137026780d9eSBradley Grove } 137126780d9eSBradley Grove 137226780d9eSBradley Grove if (!esas2r_init_msgs(a)) { 137326780d9eSBradley Grove esas2r_set_degraded_mode(a, "init messages failed"); 137426780d9eSBradley Grove goto exit; 137526780d9eSBradley Grove } 137626780d9eSBradley Grove 137726780d9eSBradley Grove /* The firmware is ready. */ 13789588d24eSBradley Grove clear_bit(AF_DEGRADED_MODE, &a->flags); 13799588d24eSBradley Grove clear_bit(AF_CHPRST_PENDING, &a->flags); 138026780d9eSBradley Grove 138126780d9eSBradley Grove /* Post all the async event requests */ 138226780d9eSBradley Grove for (i = 0, rq = a->first_ae_req; i < num_ae_requests; i++, rq++) 138326780d9eSBradley Grove esas2r_start_ae_request(a, rq); 138426780d9eSBradley Grove 138526780d9eSBradley Grove if (!a->flash_rev[0]) 138626780d9eSBradley Grove esas2r_read_flash_rev(a); 138726780d9eSBradley Grove 138826780d9eSBradley Grove if (!a->image_type[0]) 138926780d9eSBradley Grove esas2r_read_image_type(a); 139026780d9eSBradley Grove 139126780d9eSBradley Grove if (a->fw_version == 0) 139226780d9eSBradley Grove a->fw_rev[0] = 0; 139326780d9eSBradley Grove else 139426780d9eSBradley Grove sprintf(a->fw_rev, "%1d.%02d", 139526780d9eSBradley Grove (int)LOBYTE(HIWORD(a->fw_version)), 139626780d9eSBradley Grove (int)HIBYTE(HIWORD(a->fw_version))); 139726780d9eSBradley Grove 139826780d9eSBradley Grove esas2r_hdebug("firmware revision: %s", a->fw_rev); 139926780d9eSBradley Grove 14009588d24eSBradley Grove if (test_bit(AF_CHPRST_DETECTED, &a->flags) 14019588d24eSBradley Grove && (test_bit(AF_FIRST_INIT, &a->flags))) { 140226780d9eSBradley Grove esas2r_enable_chip_interrupts(a); 140326780d9eSBradley Grove return true; 140426780d9eSBradley Grove } 140526780d9eSBradley Grove 140626780d9eSBradley Grove /* initialize discovery */ 140726780d9eSBradley Grove esas2r_disc_initialize(a); 140826780d9eSBradley Grove 140926780d9eSBradley Grove /* 141026780d9eSBradley Grove * wait for the device wait time to expire here if requested. this is 141126780d9eSBradley Grove * usually requested during initial driver load and possibly when 141226780d9eSBradley Grove * resuming from a low power state. deferred device waiting will use 141326780d9eSBradley Grove * interrupts. chip reset recovery always defers device waiting to 141426780d9eSBradley Grove * avoid being in a TASKLET too long. 141526780d9eSBradley Grove */ 141626780d9eSBradley Grove if (init_poll) { 141726780d9eSBradley Grove u32 currtime = a->disc_start_time; 141826780d9eSBradley Grove u32 nexttick = 100; 141926780d9eSBradley Grove u32 deltatime; 142026780d9eSBradley Grove 142126780d9eSBradley Grove /* 142226780d9eSBradley Grove * Block Tasklets from getting scheduled and indicate this is 142326780d9eSBradley Grove * polled discovery. 142426780d9eSBradley Grove */ 14259588d24eSBradley Grove set_bit(AF_TASKLET_SCHEDULED, &a->flags); 14269588d24eSBradley Grove set_bit(AF_DISC_POLLED, &a->flags); 142726780d9eSBradley Grove 142826780d9eSBradley Grove /* 142926780d9eSBradley Grove * Temporarily bring the disable count to zero to enable 143026780d9eSBradley Grove * deferred processing. Note that the count is already zero 143126780d9eSBradley Grove * after the first initialization. 143226780d9eSBradley Grove */ 14339588d24eSBradley Grove if (test_bit(AF_FIRST_INIT, &a->flags)) 143426780d9eSBradley Grove atomic_dec(&a->disable_cnt); 143526780d9eSBradley Grove 14369588d24eSBradley Grove while (test_bit(AF_DISC_PENDING, &a->flags)) { 143726780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(100)); 143826780d9eSBradley Grove 143926780d9eSBradley Grove /* 144026780d9eSBradley Grove * Determine the need for a timer tick based on the 144126780d9eSBradley Grove * delta time between this and the last iteration of 144226780d9eSBradley Grove * this loop. We don't use the absolute time because 144326780d9eSBradley Grove * then we would have to worry about when nexttick 144426780d9eSBradley Grove * wraps and currtime hasn't yet. 144526780d9eSBradley Grove */ 144626780d9eSBradley Grove deltatime = jiffies_to_msecs(jiffies) - currtime; 144726780d9eSBradley Grove currtime += deltatime; 144826780d9eSBradley Grove 144926780d9eSBradley Grove /* 145026780d9eSBradley Grove * Process any waiting discovery as long as the chip is 145126780d9eSBradley Grove * up. If a chip reset happens during initial polling, 145226780d9eSBradley Grove * we have to make sure the timer tick processes the 145326780d9eSBradley Grove * doorbell indicating the firmware is ready. 145426780d9eSBradley Grove */ 14559588d24eSBradley Grove if (!test_bit(AF_CHPRST_PENDING, &a->flags)) 145626780d9eSBradley Grove esas2r_disc_check_for_work(a); 145726780d9eSBradley Grove 145826780d9eSBradley Grove /* Simulate a timer tick. */ 145926780d9eSBradley Grove if (nexttick <= deltatime) { 146026780d9eSBradley Grove 146126780d9eSBradley Grove /* Time for a timer tick */ 146226780d9eSBradley Grove nexttick += 100; 146326780d9eSBradley Grove esas2r_timer_tick(a); 146426780d9eSBradley Grove } 146526780d9eSBradley Grove 146626780d9eSBradley Grove if (nexttick > deltatime) 146726780d9eSBradley Grove nexttick -= deltatime; 146826780d9eSBradley Grove 146926780d9eSBradley Grove /* Do any deferred processing */ 147026780d9eSBradley Grove if (esas2r_is_tasklet_pending(a)) 147126780d9eSBradley Grove esas2r_do_tasklet_tasks(a); 147226780d9eSBradley Grove 147326780d9eSBradley Grove } 147426780d9eSBradley Grove 14759588d24eSBradley Grove if (test_bit(AF_FIRST_INIT, &a->flags)) 147626780d9eSBradley Grove atomic_inc(&a->disable_cnt); 147726780d9eSBradley Grove 14789588d24eSBradley Grove clear_bit(AF_DISC_POLLED, &a->flags); 14799588d24eSBradley Grove clear_bit(AF_TASKLET_SCHEDULED, &a->flags); 148026780d9eSBradley Grove } 148126780d9eSBradley Grove 148226780d9eSBradley Grove 148326780d9eSBradley Grove esas2r_targ_db_report_changes(a); 148426780d9eSBradley Grove 148526780d9eSBradley Grove /* 148626780d9eSBradley Grove * For cases where (a) the initialization messages processing may 148726780d9eSBradley Grove * handle an interrupt for a port event and a discovery is waiting, but 148826780d9eSBradley Grove * we are not waiting for devices, or (b) the device wait time has been 148926780d9eSBradley Grove * exhausted but there is still discovery pending, start any leftover 149026780d9eSBradley Grove * discovery in interrupt driven mode. 149126780d9eSBradley Grove */ 149226780d9eSBradley Grove esas2r_disc_start_waiting(a); 149326780d9eSBradley Grove 149426780d9eSBradley Grove /* Enable chip interrupts */ 149526780d9eSBradley Grove a->int_mask = ESAS2R_INT_STS_MASK; 149626780d9eSBradley Grove esas2r_enable_chip_interrupts(a); 149726780d9eSBradley Grove esas2r_enable_heartbeat(a); 149826780d9eSBradley Grove rslt = true; 149926780d9eSBradley Grove 150026780d9eSBradley Grove exit: 150126780d9eSBradley Grove /* 150226780d9eSBradley Grove * Regardless of whether initialization was successful, certain things 150326780d9eSBradley Grove * need to get done before we exit. 150426780d9eSBradley Grove */ 150526780d9eSBradley Grove 15069588d24eSBradley Grove if (test_bit(AF_CHPRST_DETECTED, &a->flags) && 15079588d24eSBradley Grove test_bit(AF_FIRST_INIT, &a->flags)) { 150826780d9eSBradley Grove /* 150926780d9eSBradley Grove * Reinitialization was performed during the first 151026780d9eSBradley Grove * initialization. Only clear the chip reset flag so the 151126780d9eSBradley Grove * original device polling is not cancelled. 151226780d9eSBradley Grove */ 151326780d9eSBradley Grove if (!rslt) 15149588d24eSBradley Grove clear_bit(AF_CHPRST_PENDING, &a->flags); 151526780d9eSBradley Grove } else { 151626780d9eSBradley Grove /* First initialization or a subsequent re-init is complete. */ 151726780d9eSBradley Grove if (!rslt) { 15189588d24eSBradley Grove clear_bit(AF_CHPRST_PENDING, &a->flags); 15199588d24eSBradley Grove clear_bit(AF_DISC_PENDING, &a->flags); 152026780d9eSBradley Grove } 152126780d9eSBradley Grove 152226780d9eSBradley Grove 152326780d9eSBradley Grove /* Enable deferred processing after the first initialization. */ 15249588d24eSBradley Grove if (test_bit(AF_FIRST_INIT, &a->flags)) { 15259588d24eSBradley Grove clear_bit(AF_FIRST_INIT, &a->flags); 152626780d9eSBradley Grove 152726780d9eSBradley Grove if (atomic_dec_return(&a->disable_cnt) == 0) 152826780d9eSBradley Grove esas2r_do_deferred_processes(a); 152926780d9eSBradley Grove } 153026780d9eSBradley Grove } 153126780d9eSBradley Grove 153226780d9eSBradley Grove return rslt; 153326780d9eSBradley Grove } 153426780d9eSBradley Grove 153526780d9eSBradley Grove void esas2r_reset_adapter(struct esas2r_adapter *a) 153626780d9eSBradley Grove { 15379588d24eSBradley Grove set_bit(AF_OS_RESET, &a->flags); 153826780d9eSBradley Grove esas2r_local_reset_adapter(a); 153926780d9eSBradley Grove esas2r_schedule_tasklet(a); 154026780d9eSBradley Grove } 154126780d9eSBradley Grove 154226780d9eSBradley Grove void esas2r_reset_chip(struct esas2r_adapter *a) 154326780d9eSBradley Grove { 154426780d9eSBradley Grove if (!esas2r_is_adapter_present(a)) 154526780d9eSBradley Grove return; 154626780d9eSBradley Grove 154726780d9eSBradley Grove /* 154826780d9eSBradley Grove * Before we reset the chip, save off the VDA core dump. The VDA core 154926780d9eSBradley Grove * dump is located in the upper 512KB of the onchip SRAM. Make sure 155026780d9eSBradley Grove * to not overwrite a previous crash that was saved. 155126780d9eSBradley Grove */ 15529588d24eSBradley Grove if (test_bit(AF2_COREDUMP_AVAIL, &a->flags2) && 15539588d24eSBradley Grove !test_bit(AF2_COREDUMP_SAVED, &a->flags2)) { 155426780d9eSBradley Grove esas2r_read_mem_block(a, 155526780d9eSBradley Grove a->fw_coredump_buff, 155626780d9eSBradley Grove MW_DATA_ADDR_SRAM + 0x80000, 155726780d9eSBradley Grove ESAS2R_FWCOREDUMP_SZ); 155826780d9eSBradley Grove 15599588d24eSBradley Grove set_bit(AF2_COREDUMP_SAVED, &a->flags2); 156026780d9eSBradley Grove } 156126780d9eSBradley Grove 15629588d24eSBradley Grove clear_bit(AF2_COREDUMP_AVAIL, &a->flags2); 156326780d9eSBradley Grove 156426780d9eSBradley Grove /* Reset the chip */ 156526780d9eSBradley Grove if (a->pcid->revision == MVR_FREY_B2) 156626780d9eSBradley Grove esas2r_write_register_dword(a, MU_CTL_STATUS_IN_B2, 156726780d9eSBradley Grove MU_CTL_IN_FULL_RST2); 156826780d9eSBradley Grove else 156926780d9eSBradley Grove esas2r_write_register_dword(a, MU_CTL_STATUS_IN, 157026780d9eSBradley Grove MU_CTL_IN_FULL_RST); 157126780d9eSBradley Grove 157226780d9eSBradley Grove 157326780d9eSBradley Grove /* Stall a little while to let the reset condition clear */ 157426780d9eSBradley Grove mdelay(10); 157526780d9eSBradley Grove } 157626780d9eSBradley Grove 157726780d9eSBradley Grove static void esas2r_power_down_notify_firmware(struct esas2r_adapter *a) 157826780d9eSBradley Grove { 157926780d9eSBradley Grove u32 starttime; 158026780d9eSBradley Grove u32 doorbell; 158126780d9eSBradley Grove 158226780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_POWER_DOWN); 158326780d9eSBradley Grove starttime = jiffies_to_msecs(jiffies); 158426780d9eSBradley Grove 158526780d9eSBradley Grove while (true) { 158626780d9eSBradley Grove doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT); 158726780d9eSBradley Grove if (doorbell & DRBL_POWER_DOWN) { 158826780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT, 158926780d9eSBradley Grove doorbell); 159026780d9eSBradley Grove break; 159126780d9eSBradley Grove } 159226780d9eSBradley Grove 159326780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(100)); 159426780d9eSBradley Grove 159526780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 30000) { 159626780d9eSBradley Grove esas2r_hdebug("Timeout waiting for power down"); 159726780d9eSBradley Grove break; 159826780d9eSBradley Grove } 159926780d9eSBradley Grove } 160026780d9eSBradley Grove } 160126780d9eSBradley Grove 160226780d9eSBradley Grove /* 160326780d9eSBradley Grove * Perform power management processing including managing device states, adapter 160426780d9eSBradley Grove * states, interrupts, and I/O. 160526780d9eSBradley Grove */ 160626780d9eSBradley Grove void esas2r_power_down(struct esas2r_adapter *a) 160726780d9eSBradley Grove { 16089588d24eSBradley Grove set_bit(AF_POWER_MGT, &a->flags); 16099588d24eSBradley Grove set_bit(AF_POWER_DOWN, &a->flags); 161026780d9eSBradley Grove 16119588d24eSBradley Grove if (!test_bit(AF_DEGRADED_MODE, &a->flags)) { 161226780d9eSBradley Grove u32 starttime; 161326780d9eSBradley Grove u32 doorbell; 161426780d9eSBradley Grove 161526780d9eSBradley Grove /* 161626780d9eSBradley Grove * We are currently running OK and will be reinitializing later. 161726780d9eSBradley Grove * increment the disable count to coordinate with 161826780d9eSBradley Grove * esas2r_init_adapter. We don't have to do this in degraded 161926780d9eSBradley Grove * mode since we never enabled interrupts in the first place. 162026780d9eSBradley Grove */ 162126780d9eSBradley Grove esas2r_disable_chip_interrupts(a); 162226780d9eSBradley Grove esas2r_disable_heartbeat(a); 162326780d9eSBradley Grove 162426780d9eSBradley Grove /* wait for any VDA activity to clear before continuing */ 162526780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_IN, 162626780d9eSBradley Grove DRBL_MSG_IFC_DOWN); 162726780d9eSBradley Grove starttime = jiffies_to_msecs(jiffies); 162826780d9eSBradley Grove 162926780d9eSBradley Grove while (true) { 163026780d9eSBradley Grove doorbell = 163126780d9eSBradley Grove esas2r_read_register_dword(a, MU_DOORBELL_OUT); 163226780d9eSBradley Grove if (doorbell & DRBL_MSG_IFC_DOWN) { 163326780d9eSBradley Grove esas2r_write_register_dword(a, MU_DOORBELL_OUT, 163426780d9eSBradley Grove doorbell); 163526780d9eSBradley Grove break; 163626780d9eSBradley Grove } 163726780d9eSBradley Grove 163826780d9eSBradley Grove schedule_timeout_interruptible(msecs_to_jiffies(100)); 163926780d9eSBradley Grove 164026780d9eSBradley Grove if ((jiffies_to_msecs(jiffies) - starttime) > 3000) { 164126780d9eSBradley Grove esas2r_hdebug( 164226780d9eSBradley Grove "timeout waiting for interface down"); 164326780d9eSBradley Grove break; 164426780d9eSBradley Grove } 164526780d9eSBradley Grove } 164626780d9eSBradley Grove 164726780d9eSBradley Grove /* 164826780d9eSBradley Grove * For versions of firmware that support it tell them the driver 164926780d9eSBradley Grove * is powering down. 165026780d9eSBradley Grove */ 16519588d24eSBradley Grove if (test_bit(AF2_VDA_POWER_DOWN, &a->flags2)) 165226780d9eSBradley Grove esas2r_power_down_notify_firmware(a); 165326780d9eSBradley Grove } 165426780d9eSBradley Grove 165526780d9eSBradley Grove /* Suspend I/O processing. */ 16569588d24eSBradley Grove set_bit(AF_OS_RESET, &a->flags); 16579588d24eSBradley Grove set_bit(AF_DISC_PENDING, &a->flags); 16589588d24eSBradley Grove set_bit(AF_CHPRST_PENDING, &a->flags); 165926780d9eSBradley Grove 166026780d9eSBradley Grove esas2r_process_adapter_reset(a); 166126780d9eSBradley Grove 166226780d9eSBradley Grove /* Remove devices now that I/O is cleaned up. */ 166326780d9eSBradley Grove a->prev_dev_cnt = esas2r_targ_db_get_tgt_cnt(a); 166426780d9eSBradley Grove esas2r_targ_db_remove_all(a, false); 166526780d9eSBradley Grove } 166626780d9eSBradley Grove 166726780d9eSBradley Grove /* 166826780d9eSBradley Grove * Perform power management processing including managing device states, adapter 166926780d9eSBradley Grove * states, interrupts, and I/O. 167026780d9eSBradley Grove */ 167126780d9eSBradley Grove bool esas2r_power_up(struct esas2r_adapter *a, bool init_poll) 167226780d9eSBradley Grove { 167326780d9eSBradley Grove bool ret; 167426780d9eSBradley Grove 16759588d24eSBradley Grove clear_bit(AF_POWER_DOWN, &a->flags); 167626780d9eSBradley Grove esas2r_init_pci_cfg_space(a); 16779588d24eSBradley Grove set_bit(AF_FIRST_INIT, &a->flags); 167826780d9eSBradley Grove atomic_inc(&a->disable_cnt); 167926780d9eSBradley Grove 168026780d9eSBradley Grove /* reinitialize the adapter */ 168126780d9eSBradley Grove ret = esas2r_check_adapter(a); 168226780d9eSBradley Grove if (!esas2r_init_adapter_hw(a, init_poll)) 168326780d9eSBradley Grove ret = false; 168426780d9eSBradley Grove 168526780d9eSBradley Grove /* send the reset asynchronous event */ 168626780d9eSBradley Grove esas2r_send_reset_ae(a, true); 168726780d9eSBradley Grove 168826780d9eSBradley Grove /* clear this flag after initialization. */ 16899588d24eSBradley Grove clear_bit(AF_POWER_MGT, &a->flags); 169026780d9eSBradley Grove return ret; 169126780d9eSBradley Grove } 169226780d9eSBradley Grove 169326780d9eSBradley Grove bool esas2r_is_adapter_present(struct esas2r_adapter *a) 169426780d9eSBradley Grove { 16959588d24eSBradley Grove if (test_bit(AF_NOT_PRESENT, &a->flags)) 169626780d9eSBradley Grove return false; 169726780d9eSBradley Grove 169826780d9eSBradley Grove if (esas2r_read_register_dword(a, MU_DOORBELL_OUT) == 0xFFFFFFFF) { 16999588d24eSBradley Grove set_bit(AF_NOT_PRESENT, &a->flags); 170026780d9eSBradley Grove 170126780d9eSBradley Grove return false; 170226780d9eSBradley Grove } 170326780d9eSBradley Grove return true; 170426780d9eSBradley Grove } 170526780d9eSBradley Grove 170626780d9eSBradley Grove const char *esas2r_get_model_name(struct esas2r_adapter *a) 170726780d9eSBradley Grove { 170826780d9eSBradley Grove switch (a->pcid->subsystem_device) { 170926780d9eSBradley Grove case ATTO_ESAS_R680: 171026780d9eSBradley Grove return "ATTO ExpressSAS R680"; 171126780d9eSBradley Grove 171226780d9eSBradley Grove case ATTO_ESAS_R608: 171326780d9eSBradley Grove return "ATTO ExpressSAS R608"; 171426780d9eSBradley Grove 171526780d9eSBradley Grove case ATTO_ESAS_R60F: 171626780d9eSBradley Grove return "ATTO ExpressSAS R60F"; 171726780d9eSBradley Grove 171826780d9eSBradley Grove case ATTO_ESAS_R6F0: 171926780d9eSBradley Grove return "ATTO ExpressSAS R6F0"; 172026780d9eSBradley Grove 172126780d9eSBradley Grove case ATTO_ESAS_R644: 172226780d9eSBradley Grove return "ATTO ExpressSAS R644"; 172326780d9eSBradley Grove 172426780d9eSBradley Grove case ATTO_ESAS_R648: 172526780d9eSBradley Grove return "ATTO ExpressSAS R648"; 172626780d9eSBradley Grove 172726780d9eSBradley Grove case ATTO_TSSC_3808: 172826780d9eSBradley Grove return "ATTO ThunderStream SC 3808D"; 172926780d9eSBradley Grove 173026780d9eSBradley Grove case ATTO_TSSC_3808E: 173126780d9eSBradley Grove return "ATTO ThunderStream SC 3808E"; 173226780d9eSBradley Grove 173326780d9eSBradley Grove case ATTO_TLSH_1068: 173426780d9eSBradley Grove return "ATTO ThunderLink SH 1068"; 173526780d9eSBradley Grove } 173626780d9eSBradley Grove 173726780d9eSBradley Grove return "ATTO SAS Controller"; 173826780d9eSBradley Grove } 173926780d9eSBradley Grove 174026780d9eSBradley Grove const char *esas2r_get_model_name_short(struct esas2r_adapter *a) 174126780d9eSBradley Grove { 174226780d9eSBradley Grove switch (a->pcid->subsystem_device) { 174326780d9eSBradley Grove case ATTO_ESAS_R680: 174426780d9eSBradley Grove return "R680"; 174526780d9eSBradley Grove 174626780d9eSBradley Grove case ATTO_ESAS_R608: 174726780d9eSBradley Grove return "R608"; 174826780d9eSBradley Grove 174926780d9eSBradley Grove case ATTO_ESAS_R60F: 175026780d9eSBradley Grove return "R60F"; 175126780d9eSBradley Grove 175226780d9eSBradley Grove case ATTO_ESAS_R6F0: 175326780d9eSBradley Grove return "R6F0"; 175426780d9eSBradley Grove 175526780d9eSBradley Grove case ATTO_ESAS_R644: 175626780d9eSBradley Grove return "R644"; 175726780d9eSBradley Grove 175826780d9eSBradley Grove case ATTO_ESAS_R648: 175926780d9eSBradley Grove return "R648"; 176026780d9eSBradley Grove 176126780d9eSBradley Grove case ATTO_TSSC_3808: 176226780d9eSBradley Grove return "SC 3808D"; 176326780d9eSBradley Grove 176426780d9eSBradley Grove case ATTO_TSSC_3808E: 176526780d9eSBradley Grove return "SC 3808E"; 176626780d9eSBradley Grove 176726780d9eSBradley Grove case ATTO_TLSH_1068: 176826780d9eSBradley Grove return "SH 1068"; 176926780d9eSBradley Grove } 177026780d9eSBradley Grove 177126780d9eSBradley Grove return "unknown"; 177226780d9eSBradley Grove } 1773