162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Adaptec AAC series RAID controller driver 462306a36Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based on the old aacraid driver that is.. 762306a36Sopenharmony_ci * Adaptec aacraid device driver for Linux. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 1062306a36Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 1162306a36Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Module Name: 1462306a36Sopenharmony_ci * commsup.c 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Abstract: Contain all routines that are required for FSA host/adapter 1762306a36Sopenharmony_ci * communication. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/crash_dump.h> 2362306a36Sopenharmony_ci#include <linux/types.h> 2462306a36Sopenharmony_ci#include <linux/sched.h> 2562306a36Sopenharmony_ci#include <linux/pci.h> 2662306a36Sopenharmony_ci#include <linux/spinlock.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <linux/completion.h> 2962306a36Sopenharmony_ci#include <linux/blkdev.h> 3062306a36Sopenharmony_ci#include <linux/delay.h> 3162306a36Sopenharmony_ci#include <linux/kthread.h> 3262306a36Sopenharmony_ci#include <linux/interrupt.h> 3362306a36Sopenharmony_ci#include <linux/bcd.h> 3462306a36Sopenharmony_ci#include <scsi/scsi.h> 3562306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3662306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3762306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "aacraid.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * fib_map_alloc - allocate the fib objects 4362306a36Sopenharmony_ci * @dev: Adapter to allocate for 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Allocate and map the shared PCI space for the FIB blocks used to 4662306a36Sopenharmony_ci * talk to the Adaptec firmware. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int fib_map_alloc(struct aac_dev *dev) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE) 5262306a36Sopenharmony_ci dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci dev->max_cmd_size = dev->max_fib_size; 5562306a36Sopenharmony_ci if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) { 5662306a36Sopenharmony_ci dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci dev->max_cmd_size = dev->max_fib_size; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci dprintk((KERN_INFO 6262306a36Sopenharmony_ci "allocate hardware fibs dma_alloc_coherent(%p, %d * (%d + %d), %p)\n", 6362306a36Sopenharmony_ci &dev->pdev->dev, dev->max_cmd_size, dev->scsi_host_ptr->can_queue, 6462306a36Sopenharmony_ci AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); 6562306a36Sopenharmony_ci dev->hw_fib_va = dma_alloc_coherent(&dev->pdev->dev, 6662306a36Sopenharmony_ci (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) 6762306a36Sopenharmony_ci * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), 6862306a36Sopenharmony_ci &dev->hw_fib_pa, GFP_KERNEL); 6962306a36Sopenharmony_ci if (dev->hw_fib_va == NULL) 7062306a36Sopenharmony_ci return -ENOMEM; 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/** 7562306a36Sopenharmony_ci * aac_fib_map_free - free the fib objects 7662306a36Sopenharmony_ci * @dev: Adapter to free 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Free the PCI mappings and the memory allocated for FIB blocks 7962306a36Sopenharmony_ci * on this adapter. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid aac_fib_map_free(struct aac_dev *dev) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci size_t alloc_size; 8562306a36Sopenharmony_ci size_t fib_size; 8662306a36Sopenharmony_ci int num_fibs; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if(!dev->hw_fib_va || !dev->max_cmd_size) 8962306a36Sopenharmony_ci return; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci num_fibs = dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB; 9262306a36Sopenharmony_ci fib_size = dev->max_fib_size + sizeof(struct aac_fib_xporthdr); 9362306a36Sopenharmony_ci alloc_size = fib_size * num_fibs + ALIGN32 - 1; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, alloc_size, dev->hw_fib_va, 9662306a36Sopenharmony_ci dev->hw_fib_pa); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci dev->hw_fib_va = NULL; 9962306a36Sopenharmony_ci dev->hw_fib_pa = 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid aac_fib_vector_assign(struct aac_dev *dev) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 i = 0; 10562306a36Sopenharmony_ci u32 vector = 1; 10662306a36Sopenharmony_ci struct fib *fibptr = NULL; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci for (i = 0, fibptr = &dev->fibs[i]; 10962306a36Sopenharmony_ci i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); 11062306a36Sopenharmony_ci i++, fibptr++) { 11162306a36Sopenharmony_ci if ((dev->max_msix == 1) || 11262306a36Sopenharmony_ci (i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1) 11362306a36Sopenharmony_ci - dev->vector_cap))) { 11462306a36Sopenharmony_ci fibptr->vector_no = 0; 11562306a36Sopenharmony_ci } else { 11662306a36Sopenharmony_ci fibptr->vector_no = vector; 11762306a36Sopenharmony_ci vector++; 11862306a36Sopenharmony_ci if (vector == dev->max_msix) 11962306a36Sopenharmony_ci vector = 1; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * aac_fib_setup - setup the fibs 12662306a36Sopenharmony_ci * @dev: Adapter to set up 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * Allocate the PCI space for the fibs, map it and then initialise the 12962306a36Sopenharmony_ci * fib area, the unmapped fib data and also the free list 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciint aac_fib_setup(struct aac_dev * dev) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct fib *fibptr; 13562306a36Sopenharmony_ci struct hw_fib *hw_fib; 13662306a36Sopenharmony_ci dma_addr_t hw_fib_pa; 13762306a36Sopenharmony_ci int i; 13862306a36Sopenharmony_ci u32 max_cmds; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci while (((i = fib_map_alloc(dev)) == -ENOMEM) 14162306a36Sopenharmony_ci && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) { 14262306a36Sopenharmony_ci max_cmds = (dev->scsi_host_ptr->can_queue+AAC_NUM_MGT_FIB) >> 1; 14362306a36Sopenharmony_ci dev->scsi_host_ptr->can_queue = max_cmds - AAC_NUM_MGT_FIB; 14462306a36Sopenharmony_ci if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3) 14562306a36Sopenharmony_ci dev->init->r7.max_io_commands = cpu_to_le32(max_cmds); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci if (i<0) 14862306a36Sopenharmony_ci return -ENOMEM; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci memset(dev->hw_fib_va, 0, 15162306a36Sopenharmony_ci (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) * 15262306a36Sopenharmony_ci (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* 32 byte alignment for PMC */ 15562306a36Sopenharmony_ci hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); 15662306a36Sopenharmony_ci hw_fib = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + 15762306a36Sopenharmony_ci (hw_fib_pa - dev->hw_fib_pa)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* add Xport header */ 16062306a36Sopenharmony_ci hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + 16162306a36Sopenharmony_ci sizeof(struct aac_fib_xporthdr)); 16262306a36Sopenharmony_ci hw_fib_pa += sizeof(struct aac_fib_xporthdr); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Initialise the fibs 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci for (i = 0, fibptr = &dev->fibs[i]; 16862306a36Sopenharmony_ci i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); 16962306a36Sopenharmony_ci i++, fibptr++) 17062306a36Sopenharmony_ci { 17162306a36Sopenharmony_ci fibptr->flags = 0; 17262306a36Sopenharmony_ci fibptr->size = sizeof(struct fib); 17362306a36Sopenharmony_ci fibptr->dev = dev; 17462306a36Sopenharmony_ci fibptr->hw_fib_va = hw_fib; 17562306a36Sopenharmony_ci fibptr->data = (void *) fibptr->hw_fib_va->data; 17662306a36Sopenharmony_ci fibptr->next = fibptr+1; /* Forward chain the fibs */ 17762306a36Sopenharmony_ci init_completion(&fibptr->event_wait); 17862306a36Sopenharmony_ci spin_lock_init(&fibptr->event_lock); 17962306a36Sopenharmony_ci hw_fib->header.XferState = cpu_to_le32(0xffffffff); 18062306a36Sopenharmony_ci hw_fib->header.SenderSize = 18162306a36Sopenharmony_ci cpu_to_le16(dev->max_fib_size); /* ?? max_cmd_size */ 18262306a36Sopenharmony_ci fibptr->hw_fib_pa = hw_fib_pa; 18362306a36Sopenharmony_ci fibptr->hw_sgl_pa = hw_fib_pa + 18462306a36Sopenharmony_ci offsetof(struct aac_hba_cmd_req, sge[2]); 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * one element is for the ptr to the separate sg list, 18762306a36Sopenharmony_ci * second element for 32 byte alignment 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci fibptr->hw_error_pa = hw_fib_pa + 19062306a36Sopenharmony_ci offsetof(struct aac_native_hba, resp.resp_bytes[0]); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + 19362306a36Sopenharmony_ci dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)); 19462306a36Sopenharmony_ci hw_fib_pa = hw_fib_pa + 19562306a36Sopenharmony_ci dev->max_cmd_size + sizeof(struct aac_fib_xporthdr); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci *Assign vector numbers to fibs 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci aac_fib_vector_assign(dev); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Add the fib chain to the free list 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL; 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * Set 8 fibs aside for management tools 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci dev->free_fib = &dev->fibs[dev->scsi_host_ptr->can_queue]; 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * aac_fib_alloc_tag-allocate a fib using tags 21662306a36Sopenharmony_ci * @dev: Adapter to allocate the fib for 21762306a36Sopenharmony_ci * @scmd: SCSI command 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Allocate a fib from the adapter fib pool using tags 22062306a36Sopenharmony_ci * from the blk layer. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistruct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct fib *fibptr; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci fibptr = &dev->fibs[scsi_cmd_to_rq(scmd)->tag]; 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * Null out fields that depend on being zero at the start of 23062306a36Sopenharmony_ci * each I/O 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci fibptr->hw_fib_va->header.XferState = 0; 23362306a36Sopenharmony_ci fibptr->type = FSAFS_NTC_FIB_CONTEXT; 23462306a36Sopenharmony_ci fibptr->callback_data = NULL; 23562306a36Sopenharmony_ci fibptr->callback = NULL; 23662306a36Sopenharmony_ci fibptr->flags = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return fibptr; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * aac_fib_alloc - allocate a fib 24362306a36Sopenharmony_ci * @dev: Adapter to allocate the fib for 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * Allocate a fib from the adapter fib pool. If the pool is empty we 24662306a36Sopenharmony_ci * return NULL. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistruct fib *aac_fib_alloc(struct aac_dev *dev) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct fib * fibptr; 25262306a36Sopenharmony_ci unsigned long flags; 25362306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 25462306a36Sopenharmony_ci fibptr = dev->free_fib; 25562306a36Sopenharmony_ci if(!fibptr){ 25662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 25762306a36Sopenharmony_ci return fibptr; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci dev->free_fib = fibptr->next; 26062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * Set the proper node type code and node byte size 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci fibptr->type = FSAFS_NTC_FIB_CONTEXT; 26562306a36Sopenharmony_ci fibptr->size = sizeof(struct fib); 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Null out fields that depend on being zero at the start of 26862306a36Sopenharmony_ci * each I/O 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci fibptr->hw_fib_va->header.XferState = 0; 27162306a36Sopenharmony_ci fibptr->flags = 0; 27262306a36Sopenharmony_ci fibptr->callback = NULL; 27362306a36Sopenharmony_ci fibptr->callback_data = NULL; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return fibptr; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/** 27962306a36Sopenharmony_ci * aac_fib_free - free a fib 28062306a36Sopenharmony_ci * @fibptr: fib to free up 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * Frees up a fib and places it on the appropriate queue 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_civoid aac_fib_free(struct fib *fibptr) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci unsigned long flags; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (fibptr->done == 2) 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci spin_lock_irqsave(&fibptr->dev->fib_lock, flags); 29362306a36Sopenharmony_ci if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) 29462306a36Sopenharmony_ci aac_config.fib_timeouts++; 29562306a36Sopenharmony_ci if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) && 29662306a36Sopenharmony_ci fibptr->hw_fib_va->header.XferState != 0) { 29762306a36Sopenharmony_ci printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 29862306a36Sopenharmony_ci (void*)fibptr, 29962306a36Sopenharmony_ci le32_to_cpu(fibptr->hw_fib_va->header.XferState)); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci fibptr->next = fibptr->dev->free_fib; 30262306a36Sopenharmony_ci fibptr->dev->free_fib = fibptr; 30362306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * aac_fib_init - initialise a fib 30862306a36Sopenharmony_ci * @fibptr: The fib to initialize 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * Set up the generic fib fields ready for use 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_civoid aac_fib_init(struct fib *fibptr) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct hw_fib *hw_fib = fibptr->hw_fib_va; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci memset(&hw_fib->header, 0, sizeof(struct aac_fibhdr)); 31862306a36Sopenharmony_ci hw_fib->header.StructType = FIB_MAGIC; 31962306a36Sopenharmony_ci hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size); 32062306a36Sopenharmony_ci hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); 32162306a36Sopenharmony_ci hw_fib->header.u.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa); 32262306a36Sopenharmony_ci hw_fib->header.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/** 32662306a36Sopenharmony_ci * fib_dealloc - deallocate a fib 32762306a36Sopenharmony_ci * @fibptr: fib to deallocate 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Will deallocate and return to the free pool the FIB pointed to by the 33062306a36Sopenharmony_ci * caller. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void fib_dealloc(struct fib * fibptr) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct hw_fib *hw_fib = fibptr->hw_fib_va; 33662306a36Sopenharmony_ci hw_fib->header.XferState = 0; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* 34062306a36Sopenharmony_ci * Commuication primitives define and support the queuing method we use to 34162306a36Sopenharmony_ci * support host to adapter commuication. All queue accesses happen through 34262306a36Sopenharmony_ci * these routines and are the only routines which have a knowledge of the 34362306a36Sopenharmony_ci * how these queues are implemented. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * aac_get_entry - get a queue entry 34862306a36Sopenharmony_ci * @dev: Adapter 34962306a36Sopenharmony_ci * @qid: Queue Number 35062306a36Sopenharmony_ci * @entry: Entry return 35162306a36Sopenharmony_ci * @index: Index return 35262306a36Sopenharmony_ci * @nonotify: notification control 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * With a priority the routine returns a queue entry if the queue has free entries. If the queue 35562306a36Sopenharmony_ci * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is 35662306a36Sopenharmony_ci * returned. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct aac_queue * q; 36262306a36Sopenharmony_ci unsigned long idx; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * All of the queues wrap when they reach the end, so we check 36662306a36Sopenharmony_ci * to see if they have reached the end and if they have we just 36762306a36Sopenharmony_ci * set the index back to zero. This is a wrap. You could or off 36862306a36Sopenharmony_ci * the high bits in all updates but this is a bit faster I think. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci q = &dev->queues->queue[qid]; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci idx = *index = le32_to_cpu(*(q->headers.producer)); 37462306a36Sopenharmony_ci /* Interrupt Moderation, only interrupt for first two entries */ 37562306a36Sopenharmony_ci if (idx != le32_to_cpu(*(q->headers.consumer))) { 37662306a36Sopenharmony_ci if (--idx == 0) { 37762306a36Sopenharmony_ci if (qid == AdapNormCmdQueue) 37862306a36Sopenharmony_ci idx = ADAP_NORM_CMD_ENTRIES; 37962306a36Sopenharmony_ci else 38062306a36Sopenharmony_ci idx = ADAP_NORM_RESP_ENTRIES; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci if (idx != le32_to_cpu(*(q->headers.consumer))) 38362306a36Sopenharmony_ci *nonotify = 1; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (qid == AdapNormCmdQueue) { 38762306a36Sopenharmony_ci if (*index >= ADAP_NORM_CMD_ENTRIES) 38862306a36Sopenharmony_ci *index = 0; /* Wrap to front of the Producer Queue. */ 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci if (*index >= ADAP_NORM_RESP_ENTRIES) 39162306a36Sopenharmony_ci *index = 0; /* Wrap to front of the Producer Queue. */ 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Queue is full */ 39562306a36Sopenharmony_ci if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { 39662306a36Sopenharmony_ci printk(KERN_WARNING "Queue %d full, %u outstanding.\n", 39762306a36Sopenharmony_ci qid, atomic_read(&q->numpending)); 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci } else { 40062306a36Sopenharmony_ci *entry = q->base + *index; 40162306a36Sopenharmony_ci return 1; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/** 40662306a36Sopenharmony_ci * aac_queue_get - get the next free QE 40762306a36Sopenharmony_ci * @dev: Adapter 40862306a36Sopenharmony_ci * @index: Returned index 40962306a36Sopenharmony_ci * @qid: Queue number 41062306a36Sopenharmony_ci * @hw_fib: Fib to associate with the queue entry 41162306a36Sopenharmony_ci * @wait: Wait if queue full 41262306a36Sopenharmony_ci * @fibptr: Driver fib object to go with fib 41362306a36Sopenharmony_ci * @nonotify: Don't notify the adapter 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * Gets the next free QE off the requested priorty adapter command 41662306a36Sopenharmony_ci * queue and associates the Fib with the QE. The QE represented by 41762306a36Sopenharmony_ci * index is ready to insert on the queue when this routine returns 41862306a36Sopenharmony_ci * success. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciint aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct aac_entry * entry = NULL; 42462306a36Sopenharmony_ci int map = 0; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (qid == AdapNormCmdQueue) { 42762306a36Sopenharmony_ci /* if no entries wait for some if caller wants to */ 42862306a36Sopenharmony_ci while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { 42962306a36Sopenharmony_ci printk(KERN_ERR "GetEntries failed\n"); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci /* 43262306a36Sopenharmony_ci * Setup queue entry with a command, status and fib mapped 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); 43562306a36Sopenharmony_ci map = 1; 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { 43862306a36Sopenharmony_ci /* if no entries wait for some if caller wants to */ 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci /* 44162306a36Sopenharmony_ci * Setup queue entry with command, status and fib mapped 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); 44462306a36Sopenharmony_ci entry->addr = hw_fib->header.SenderFibAddress; 44562306a36Sopenharmony_ci /* Restore adapters pointer to the FIB */ 44662306a36Sopenharmony_ci hw_fib->header.u.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ 44762306a36Sopenharmony_ci map = 0; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * If MapFib is true than we need to map the Fib and put pointers 45162306a36Sopenharmony_ci * in the queue entry. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci if (map) 45462306a36Sopenharmony_ci entry->addr = cpu_to_le32(fibptr->hw_fib_pa); 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* 45962306a36Sopenharmony_ci * Define the highest level of host to adapter communication routines. 46062306a36Sopenharmony_ci * These routines will support host to adapter FS commuication. These 46162306a36Sopenharmony_ci * routines have no knowledge of the commuication method used. This level 46262306a36Sopenharmony_ci * sends and receives FIBs. This level has no knowledge of how these FIBs 46362306a36Sopenharmony_ci * get passed back and forth. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/** 46762306a36Sopenharmony_ci * aac_fib_send - send a fib to the adapter 46862306a36Sopenharmony_ci * @command: Command to send 46962306a36Sopenharmony_ci * @fibptr: The fib 47062306a36Sopenharmony_ci * @size: Size of fib data area 47162306a36Sopenharmony_ci * @priority: Priority of Fib 47262306a36Sopenharmony_ci * @wait: Async/sync select 47362306a36Sopenharmony_ci * @reply: True if a reply is wanted 47462306a36Sopenharmony_ci * @callback: Called with reply 47562306a36Sopenharmony_ci * @callback_data: Passed to callback 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * Sends the requested FIB to the adapter and optionally will wait for a 47862306a36Sopenharmony_ci * response FIB. If the caller does not wish to wait for a response than 47962306a36Sopenharmony_ci * an event to wait on must be supplied. This event will be set when a 48062306a36Sopenharmony_ci * response FIB is received from the adapter. 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ciint aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, 48462306a36Sopenharmony_ci int priority, int wait, int reply, fib_callback callback, 48562306a36Sopenharmony_ci void *callback_data) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct aac_dev * dev = fibptr->dev; 48862306a36Sopenharmony_ci struct hw_fib * hw_fib = fibptr->hw_fib_va; 48962306a36Sopenharmony_ci unsigned long flags = 0; 49062306a36Sopenharmony_ci unsigned long mflags = 0; 49162306a36Sopenharmony_ci unsigned long sflags = 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned))) 49462306a36Sopenharmony_ci return -EBUSY; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)) 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * There are 5 cases with the wait and response requested flags. 50162306a36Sopenharmony_ci * The only invalid cases are if the caller requests to wait and 50262306a36Sopenharmony_ci * does not request a response and if the caller does not want a 50362306a36Sopenharmony_ci * response and the Fib is not allocated from pool. If a response 50462306a36Sopenharmony_ci * is not requested the Fib will just be deallocaed by the DPC 50562306a36Sopenharmony_ci * routine when the response comes back from the adapter. No 50662306a36Sopenharmony_ci * further processing will be done besides deleting the Fib. We 50762306a36Sopenharmony_ci * will have a debug mode where the adapter can notify the host 50862306a36Sopenharmony_ci * it had a problem and the host can log that fact. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci fibptr->flags = 0; 51162306a36Sopenharmony_ci if (wait && !reply) { 51262306a36Sopenharmony_ci return -EINVAL; 51362306a36Sopenharmony_ci } else if (!wait && reply) { 51462306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(Async | ResponseExpected); 51562306a36Sopenharmony_ci FIB_COUNTER_INCREMENT(aac_config.AsyncSent); 51662306a36Sopenharmony_ci } else if (!wait && !reply) { 51762306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(NoResponseExpected); 51862306a36Sopenharmony_ci FIB_COUNTER_INCREMENT(aac_config.NoResponseSent); 51962306a36Sopenharmony_ci } else if (wait && reply) { 52062306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(ResponseExpected); 52162306a36Sopenharmony_ci FIB_COUNTER_INCREMENT(aac_config.NormalSent); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci /* 52462306a36Sopenharmony_ci * Map the fib into 32bits by using the fib number 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci hw_fib->header.SenderFibAddress = 52862306a36Sopenharmony_ci cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* use the same shifted value for handle to be compatible 53162306a36Sopenharmony_ci * with the new native hba command handle 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_ci hw_fib->header.Handle = 53462306a36Sopenharmony_ci cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * Set FIB state to indicate where it came from and if we want a 53862306a36Sopenharmony_ci * response from the adapter. Also load the command from the 53962306a36Sopenharmony_ci * caller. 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * Map the hw fib pointer as a 32bit value 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci hw_fib->header.Command = cpu_to_le16(command); 54462306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(SentFromHost); 54562306a36Sopenharmony_ci /* 54662306a36Sopenharmony_ci * Set the size of the Fib we want to send to the adapter 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); 54962306a36Sopenharmony_ci if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) { 55062306a36Sopenharmony_ci return -EMSGSIZE; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci /* 55362306a36Sopenharmony_ci * Get a queue entry connect the FIB to it and send an notify 55462306a36Sopenharmony_ci * the adapter a command is ready. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(NormalPriority); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* 55962306a36Sopenharmony_ci * Fill in the Callback and CallbackContext if we are not 56062306a36Sopenharmony_ci * going to wait. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ci if (!wait) { 56362306a36Sopenharmony_ci fibptr->callback = callback; 56462306a36Sopenharmony_ci fibptr->callback_data = callback_data; 56562306a36Sopenharmony_ci fibptr->flags = FIB_CONTEXT_FLAG; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci fibptr->done = 0; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci FIB_COUNTER_INCREMENT(aac_config.FibsSent); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci dprintk((KERN_DEBUG "Fib contents:.\n")); 57362306a36Sopenharmony_ci dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command))); 57462306a36Sopenharmony_ci dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command))); 57562306a36Sopenharmony_ci dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState))); 57662306a36Sopenharmony_ci dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va)); 57762306a36Sopenharmony_ci dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa)); 57862306a36Sopenharmony_ci dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr)); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (!dev->queues) 58162306a36Sopenharmony_ci return -EBUSY; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (wait) { 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci spin_lock_irqsave(&dev->manage_lock, mflags); 58662306a36Sopenharmony_ci if (dev->management_fib_count >= AAC_NUM_MGT_FIB) { 58762306a36Sopenharmony_ci printk(KERN_INFO "No management Fibs Available:%d\n", 58862306a36Sopenharmony_ci dev->management_fib_count); 58962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 59062306a36Sopenharmony_ci return -EBUSY; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci dev->management_fib_count++; 59362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 59462306a36Sopenharmony_ci spin_lock_irqsave(&fibptr->event_lock, flags); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (dev->sync_mode) { 59862306a36Sopenharmony_ci if (wait) 59962306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 60062306a36Sopenharmony_ci spin_lock_irqsave(&dev->sync_lock, sflags); 60162306a36Sopenharmony_ci if (dev->sync_fib) { 60262306a36Sopenharmony_ci list_add_tail(&fibptr->fiblink, &dev->sync_fib_list); 60362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_lock, sflags); 60462306a36Sopenharmony_ci } else { 60562306a36Sopenharmony_ci dev->sync_fib = fibptr; 60662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_lock, sflags); 60762306a36Sopenharmony_ci aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, 60862306a36Sopenharmony_ci (u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0, 60962306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci if (wait) { 61262306a36Sopenharmony_ci fibptr->flags |= FIB_CONTEXT_FLAG_WAIT; 61362306a36Sopenharmony_ci if (wait_for_completion_interruptible(&fibptr->event_wait)) { 61462306a36Sopenharmony_ci fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT; 61562306a36Sopenharmony_ci return -EFAULT; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci return -EINPROGRESS; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (aac_adapter_deliver(fibptr) != 0) { 62362306a36Sopenharmony_ci printk(KERN_ERR "aac_fib_send: returned -EBUSY\n"); 62462306a36Sopenharmony_ci if (wait) { 62562306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 62662306a36Sopenharmony_ci spin_lock_irqsave(&dev->manage_lock, mflags); 62762306a36Sopenharmony_ci dev->management_fib_count--; 62862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci return -EBUSY; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* 63562306a36Sopenharmony_ci * If the caller wanted us to wait for response wait now. 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (wait) { 63962306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 64062306a36Sopenharmony_ci /* Only set for first known interruptable command */ 64162306a36Sopenharmony_ci if (wait < 0) { 64262306a36Sopenharmony_ci /* 64362306a36Sopenharmony_ci * *VERY* Dangerous to time out a command, the 64462306a36Sopenharmony_ci * assumption is made that we have no hope of 64562306a36Sopenharmony_ci * functioning because an interrupt routing or other 64662306a36Sopenharmony_ci * hardware failure has occurred. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci unsigned long timeout = jiffies + (180 * HZ); /* 3 minutes */ 64962306a36Sopenharmony_ci while (!try_wait_for_completion(&fibptr->event_wait)) { 65062306a36Sopenharmony_ci int blink; 65162306a36Sopenharmony_ci if (time_is_before_eq_jiffies(timeout)) { 65262306a36Sopenharmony_ci struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue]; 65362306a36Sopenharmony_ci atomic_dec(&q->numpending); 65462306a36Sopenharmony_ci if (wait == -1) { 65562306a36Sopenharmony_ci printk(KERN_ERR "aacraid: aac_fib_send: first asynchronous command timed out.\n" 65662306a36Sopenharmony_ci "Usually a result of a PCI interrupt routing problem;\n" 65762306a36Sopenharmony_ci "update mother board BIOS or consider utilizing one of\n" 65862306a36Sopenharmony_ci "the SAFE mode kernel options (acpi, apic etc)\n"); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci return -ETIMEDOUT; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (unlikely(aac_pci_offline(dev))) 66462306a36Sopenharmony_ci return -EFAULT; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if ((blink = aac_adapter_check_health(dev)) > 0) { 66762306a36Sopenharmony_ci if (wait == -1) { 66862306a36Sopenharmony_ci printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n" 66962306a36Sopenharmony_ci "Usually a result of a serious unrecoverable hardware problem\n", 67062306a36Sopenharmony_ci blink); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci return -EFAULT; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Allow other processes / CPUS to use core 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_ci schedule(); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci } else if (wait_for_completion_interruptible(&fibptr->event_wait)) { 68062306a36Sopenharmony_ci /* Do nothing ... satisfy 68162306a36Sopenharmony_ci * wait_for_completion_interruptible must_check */ 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci spin_lock_irqsave(&fibptr->event_lock, flags); 68562306a36Sopenharmony_ci if (fibptr->done == 0) { 68662306a36Sopenharmony_ci fibptr->done = 2; /* Tell interrupt we aborted */ 68762306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 68862306a36Sopenharmony_ci return -ERESTARTSYS; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 69162306a36Sopenharmony_ci BUG_ON(fibptr->done == 0); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) 69462306a36Sopenharmony_ci return -ETIMEDOUT; 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci /* 69862306a36Sopenharmony_ci * If the user does not want a response than return success otherwise 69962306a36Sopenharmony_ci * return pending 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci if (reply) 70262306a36Sopenharmony_ci return -EINPROGRESS; 70362306a36Sopenharmony_ci else 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ciint aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback, 70862306a36Sopenharmony_ci void *callback_data) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct aac_dev *dev = fibptr->dev; 71162306a36Sopenharmony_ci int wait; 71262306a36Sopenharmony_ci unsigned long flags = 0; 71362306a36Sopenharmony_ci unsigned long mflags = 0; 71462306a36Sopenharmony_ci struct aac_hba_cmd_req *hbacmd = (struct aac_hba_cmd_req *) 71562306a36Sopenharmony_ci fibptr->hw_fib_va; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci fibptr->flags = (FIB_CONTEXT_FLAG | FIB_CONTEXT_FLAG_NATIVE_HBA); 71862306a36Sopenharmony_ci if (callback) { 71962306a36Sopenharmony_ci wait = 0; 72062306a36Sopenharmony_ci fibptr->callback = callback; 72162306a36Sopenharmony_ci fibptr->callback_data = callback_data; 72262306a36Sopenharmony_ci } else 72362306a36Sopenharmony_ci wait = 1; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci hbacmd->iu_type = command; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (command == HBA_IU_TYPE_SCSI_CMD_REQ) { 72962306a36Sopenharmony_ci /* bit1 of request_id must be 0 */ 73062306a36Sopenharmony_ci hbacmd->request_id = 73162306a36Sopenharmony_ci cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); 73262306a36Sopenharmony_ci fibptr->flags |= FIB_CONTEXT_FLAG_SCSI_CMD; 73362306a36Sopenharmony_ci } else 73462306a36Sopenharmony_ci return -EINVAL; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (wait) { 73862306a36Sopenharmony_ci spin_lock_irqsave(&dev->manage_lock, mflags); 73962306a36Sopenharmony_ci if (dev->management_fib_count >= AAC_NUM_MGT_FIB) { 74062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 74162306a36Sopenharmony_ci return -EBUSY; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci dev->management_fib_count++; 74462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 74562306a36Sopenharmony_ci spin_lock_irqsave(&fibptr->event_lock, flags); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (aac_adapter_deliver(fibptr) != 0) { 74962306a36Sopenharmony_ci if (wait) { 75062306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 75162306a36Sopenharmony_ci spin_lock_irqsave(&dev->manage_lock, mflags); 75262306a36Sopenharmony_ci dev->management_fib_count--; 75362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->manage_lock, mflags); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci return -EBUSY; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci FIB_COUNTER_INCREMENT(aac_config.NativeSent); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (wait) { 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (unlikely(aac_pci_offline(dev))) 76462306a36Sopenharmony_ci return -EFAULT; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci fibptr->flags |= FIB_CONTEXT_FLAG_WAIT; 76762306a36Sopenharmony_ci if (wait_for_completion_interruptible(&fibptr->event_wait)) 76862306a36Sopenharmony_ci fibptr->done = 2; 76962306a36Sopenharmony_ci fibptr->flags &= ~(FIB_CONTEXT_FLAG_WAIT); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci spin_lock_irqsave(&fibptr->event_lock, flags); 77262306a36Sopenharmony_ci if ((fibptr->done == 0) || (fibptr->done == 2)) { 77362306a36Sopenharmony_ci fibptr->done = 2; /* Tell interrupt we aborted */ 77462306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 77562306a36Sopenharmony_ci return -ERESTARTSYS; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci spin_unlock_irqrestore(&fibptr->event_lock, flags); 77862306a36Sopenharmony_ci WARN_ON(fibptr->done == 0); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) 78162306a36Sopenharmony_ci return -ETIMEDOUT; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return -EINPROGRESS; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * aac_consumer_get - get the top of the queue 79162306a36Sopenharmony_ci * @dev: Adapter 79262306a36Sopenharmony_ci * @q: Queue 79362306a36Sopenharmony_ci * @entry: Return entry 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci * Will return a pointer to the entry on the top of the queue requested that 79662306a36Sopenharmony_ci * we are a consumer of, and return the address of the queue entry. It does 79762306a36Sopenharmony_ci * not change the state of the queue. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ciint aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci u32 index; 80362306a36Sopenharmony_ci int status; 80462306a36Sopenharmony_ci if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) { 80562306a36Sopenharmony_ci status = 0; 80662306a36Sopenharmony_ci } else { 80762306a36Sopenharmony_ci /* 80862306a36Sopenharmony_ci * The consumer index must be wrapped if we have reached 80962306a36Sopenharmony_ci * the end of the queue, else we just use the entry 81062306a36Sopenharmony_ci * pointed to by the header index 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_ci if (le32_to_cpu(*q->headers.consumer) >= q->entries) 81362306a36Sopenharmony_ci index = 0; 81462306a36Sopenharmony_ci else 81562306a36Sopenharmony_ci index = le32_to_cpu(*q->headers.consumer); 81662306a36Sopenharmony_ci *entry = q->base + index; 81762306a36Sopenharmony_ci status = 1; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci return(status); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/** 82362306a36Sopenharmony_ci * aac_consumer_free - free consumer entry 82462306a36Sopenharmony_ci * @dev: Adapter 82562306a36Sopenharmony_ci * @q: Queue 82662306a36Sopenharmony_ci * @qid: Queue ident 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * Frees up the current top of the queue we are a consumer of. If the 82962306a36Sopenharmony_ci * queue was full notify the producer that the queue is no longer full. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_civoid aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci int wasfull = 0; 83562306a36Sopenharmony_ci u32 notify; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer)) 83862306a36Sopenharmony_ci wasfull = 1; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (le32_to_cpu(*q->headers.consumer) >= q->entries) 84162306a36Sopenharmony_ci *q->headers.consumer = cpu_to_le32(1); 84262306a36Sopenharmony_ci else 84362306a36Sopenharmony_ci le32_add_cpu(q->headers.consumer, 1); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (wasfull) { 84662306a36Sopenharmony_ci switch (qid) { 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci case HostNormCmdQueue: 84962306a36Sopenharmony_ci notify = HostNormCmdNotFull; 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci case HostNormRespQueue: 85262306a36Sopenharmony_ci notify = HostNormRespNotFull; 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci default: 85562306a36Sopenharmony_ci BUG(); 85662306a36Sopenharmony_ci return; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci aac_adapter_notify(dev, notify); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/** 86362306a36Sopenharmony_ci * aac_fib_adapter_complete - complete adapter issued fib 86462306a36Sopenharmony_ci * @fibptr: fib to complete 86562306a36Sopenharmony_ci * @size: size of fib 86662306a36Sopenharmony_ci * 86762306a36Sopenharmony_ci * Will do all necessary work to complete a FIB that was sent from 86862306a36Sopenharmony_ci * the adapter. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ciint aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct hw_fib * hw_fib = fibptr->hw_fib_va; 87462306a36Sopenharmony_ci struct aac_dev * dev = fibptr->dev; 87562306a36Sopenharmony_ci struct aac_queue * q; 87662306a36Sopenharmony_ci unsigned long nointr = 0; 87762306a36Sopenharmony_ci unsigned long qflags; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 || 88062306a36Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 88162306a36Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { 88262306a36Sopenharmony_ci kfree(hw_fib); 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (hw_fib->header.XferState == 0) { 88762306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE) 88862306a36Sopenharmony_ci kfree(hw_fib); 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci /* 89262306a36Sopenharmony_ci * If we plan to do anything check the structure type first. 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_ci if (hw_fib->header.StructType != FIB_MAGIC && 89562306a36Sopenharmony_ci hw_fib->header.StructType != FIB_MAGIC2 && 89662306a36Sopenharmony_ci hw_fib->header.StructType != FIB_MAGIC2_64) { 89762306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE) 89862306a36Sopenharmony_ci kfree(hw_fib); 89962306a36Sopenharmony_ci return -EINVAL; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci /* 90262306a36Sopenharmony_ci * This block handles the case where the adapter had sent us a 90362306a36Sopenharmony_ci * command and we have finished processing the command. We 90462306a36Sopenharmony_ci * call completeFib when we are done processing the command 90562306a36Sopenharmony_ci * and want to send a response back to the adapter. This will 90662306a36Sopenharmony_ci * send the completed cdb to the adapter. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) { 90962306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE) { 91062306a36Sopenharmony_ci kfree (hw_fib); 91162306a36Sopenharmony_ci } else { 91262306a36Sopenharmony_ci u32 index; 91362306a36Sopenharmony_ci hw_fib->header.XferState |= cpu_to_le32(HostProcessed); 91462306a36Sopenharmony_ci if (size) { 91562306a36Sopenharmony_ci size += sizeof(struct aac_fibhdr); 91662306a36Sopenharmony_ci if (size > le16_to_cpu(hw_fib->header.SenderSize)) 91762306a36Sopenharmony_ci return -EMSGSIZE; 91862306a36Sopenharmony_ci hw_fib->header.Size = cpu_to_le16(size); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci q = &dev->queues->queue[AdapNormRespQueue]; 92162306a36Sopenharmony_ci spin_lock_irqsave(q->lock, qflags); 92262306a36Sopenharmony_ci aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr); 92362306a36Sopenharmony_ci *(q->headers.producer) = cpu_to_le32(index + 1); 92462306a36Sopenharmony_ci spin_unlock_irqrestore(q->lock, qflags); 92562306a36Sopenharmony_ci if (!(nointr & (int)aac_config.irq_mod)) 92662306a36Sopenharmony_ci aac_adapter_notify(dev, AdapNormRespQueue); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci } else { 92962306a36Sopenharmony_ci printk(KERN_WARNING "aac_fib_adapter_complete: " 93062306a36Sopenharmony_ci "Unknown xferstate detected.\n"); 93162306a36Sopenharmony_ci BUG(); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci/** 93762306a36Sopenharmony_ci * aac_fib_complete - fib completion handler 93862306a36Sopenharmony_ci * @fibptr: FIB to complete 93962306a36Sopenharmony_ci * 94062306a36Sopenharmony_ci * Will do all necessary work to complete a FIB. 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ciint aac_fib_complete(struct fib *fibptr) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct hw_fib * hw_fib = fibptr->hw_fib_va; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) { 94862306a36Sopenharmony_ci fib_dealloc(fibptr); 94962306a36Sopenharmony_ci return 0; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* 95362306a36Sopenharmony_ci * Check for a fib which has already been completed or with a 95462306a36Sopenharmony_ci * status wait timeout 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (hw_fib->header.XferState == 0 || fibptr->done == 2) 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci /* 96062306a36Sopenharmony_ci * If we plan to do anything check the structure type first. 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (hw_fib->header.StructType != FIB_MAGIC && 96462306a36Sopenharmony_ci hw_fib->header.StructType != FIB_MAGIC2 && 96562306a36Sopenharmony_ci hw_fib->header.StructType != FIB_MAGIC2_64) 96662306a36Sopenharmony_ci return -EINVAL; 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * This block completes a cdb which orginated on the host and we 96962306a36Sopenharmony_ci * just need to deallocate the cdb or reinit it. At this point the 97062306a36Sopenharmony_ci * command is complete that we had sent to the adapter and this 97162306a36Sopenharmony_ci * cdb could be reused. 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) && 97562306a36Sopenharmony_ci (hw_fib->header.XferState & cpu_to_le32(AdapterProcessed))) 97662306a36Sopenharmony_ci { 97762306a36Sopenharmony_ci fib_dealloc(fibptr); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost)) 98062306a36Sopenharmony_ci { 98162306a36Sopenharmony_ci /* 98262306a36Sopenharmony_ci * This handles the case when the host has aborted the I/O 98362306a36Sopenharmony_ci * to the adapter because the adapter is not responding 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci fib_dealloc(fibptr); 98662306a36Sopenharmony_ci } else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) { 98762306a36Sopenharmony_ci fib_dealloc(fibptr); 98862306a36Sopenharmony_ci } else { 98962306a36Sopenharmony_ci BUG(); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/** 99562306a36Sopenharmony_ci * aac_printf - handle printf from firmware 99662306a36Sopenharmony_ci * @dev: Adapter 99762306a36Sopenharmony_ci * @val: Message info 99862306a36Sopenharmony_ci * 99962306a36Sopenharmony_ci * Print a message passed to us by the controller firmware on the 100062306a36Sopenharmony_ci * Adaptec board 100162306a36Sopenharmony_ci */ 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_civoid aac_printf(struct aac_dev *dev, u32 val) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci char *cp = dev->printfbuf; 100662306a36Sopenharmony_ci if (dev->printf_enabled) 100762306a36Sopenharmony_ci { 100862306a36Sopenharmony_ci int length = val & 0xffff; 100962306a36Sopenharmony_ci int level = (val >> 16) & 0xffff; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* 101262306a36Sopenharmony_ci * The size of the printfbuf is set in port.c 101362306a36Sopenharmony_ci * There is no variable or define for it 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci if (length > 255) 101662306a36Sopenharmony_ci length = 255; 101762306a36Sopenharmony_ci if (cp[length] != 0) 101862306a36Sopenharmony_ci cp[length] = 0; 101962306a36Sopenharmony_ci if (level == LOG_AAC_HIGH_ERROR) 102062306a36Sopenharmony_ci printk(KERN_WARNING "%s:%s", dev->name, cp); 102162306a36Sopenharmony_ci else 102262306a36Sopenharmony_ci printk(KERN_INFO "%s:%s", dev->name, cp); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci memset(cp, 0, 256); 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic inline int aac_aif_data(struct aac_aifcmd *aifcmd, uint32_t index) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci return le32_to_cpu(((__le32 *)aifcmd->data)[index]); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic void aac_handle_aif_bu(struct aac_dev *dev, struct aac_aifcmd *aifcmd) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci switch (aac_aif_data(aifcmd, 1)) { 103662306a36Sopenharmony_ci case AifBuCacheDataLoss: 103762306a36Sopenharmony_ci if (aac_aif_data(aifcmd, 2)) 103862306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "Backup unit had cache data loss - [%d]\n", 103962306a36Sopenharmony_ci aac_aif_data(aifcmd, 2)); 104062306a36Sopenharmony_ci else 104162306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "Backup Unit had cache data loss\n"); 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case AifBuCacheDataRecover: 104462306a36Sopenharmony_ci if (aac_aif_data(aifcmd, 2)) 104562306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "DDR cache data recovered successfully - [%d]\n", 104662306a36Sopenharmony_ci aac_aif_data(aifcmd, 2)); 104762306a36Sopenharmony_ci else 104862306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "DDR cache data recovered successfully\n"); 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci#define AIF_SNIFF_TIMEOUT (500*HZ) 105462306a36Sopenharmony_ci/** 105562306a36Sopenharmony_ci * aac_handle_aif - Handle a message from the firmware 105662306a36Sopenharmony_ci * @dev: Which adapter this fib is from 105762306a36Sopenharmony_ci * @fibptr: Pointer to fibptr from adapter 105862306a36Sopenharmony_ci * 105962306a36Sopenharmony_ci * This routine handles a driver notify fib from the adapter and 106062306a36Sopenharmony_ci * dispatches it to the appropriate routine for handling. 106162306a36Sopenharmony_ci */ 106262306a36Sopenharmony_cistatic void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci struct hw_fib * hw_fib = fibptr->hw_fib_va; 106562306a36Sopenharmony_ci struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; 106662306a36Sopenharmony_ci u32 channel, id, lun, container; 106762306a36Sopenharmony_ci struct scsi_device *device; 106862306a36Sopenharmony_ci enum { 106962306a36Sopenharmony_ci NOTHING, 107062306a36Sopenharmony_ci DELETE, 107162306a36Sopenharmony_ci ADD, 107262306a36Sopenharmony_ci CHANGE 107362306a36Sopenharmony_ci } device_config_needed = NOTHING; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Sniff for container changes */ 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (!dev || !dev->fsa_dev) 107862306a36Sopenharmony_ci return; 107962306a36Sopenharmony_ci container = channel = id = lun = (u32)-1; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* 108262306a36Sopenharmony_ci * We have set this up to try and minimize the number of 108362306a36Sopenharmony_ci * re-configures that take place. As a result of this when 108462306a36Sopenharmony_ci * certain AIF's come in we will set a flag waiting for another 108562306a36Sopenharmony_ci * type of AIF before setting the re-config flag. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci switch (le32_to_cpu(aifcmd->command)) { 108862306a36Sopenharmony_ci case AifCmdDriverNotify: 108962306a36Sopenharmony_ci switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { 109062306a36Sopenharmony_ci case AifRawDeviceRemove: 109162306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 109262306a36Sopenharmony_ci if ((container >> 28)) { 109362306a36Sopenharmony_ci container = (u32)-1; 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci channel = (container >> 24) & 0xF; 109762306a36Sopenharmony_ci if (channel >= dev->maximum_num_channels) { 109862306a36Sopenharmony_ci container = (u32)-1; 109962306a36Sopenharmony_ci break; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci id = container & 0xFFFF; 110262306a36Sopenharmony_ci if (id >= dev->maximum_num_physicals) { 110362306a36Sopenharmony_ci container = (u32)-1; 110462306a36Sopenharmony_ci break; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci lun = (container >> 16) & 0xFF; 110762306a36Sopenharmony_ci container = (u32)-1; 110862306a36Sopenharmony_ci channel = aac_phys_to_logical(channel); 110962306a36Sopenharmony_ci device_config_needed = DELETE; 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* 111362306a36Sopenharmony_ci * Morph or Expand complete 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci case AifDenMorphComplete: 111662306a36Sopenharmony_ci case AifDenVolumeExtendComplete: 111762306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 111862306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 111962306a36Sopenharmony_ci break; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* 112262306a36Sopenharmony_ci * Find the scsi_device associated with the SCSI 112362306a36Sopenharmony_ci * address. Make sure we have the right array, and if 112462306a36Sopenharmony_ci * so set the flag to initiate a new re-config once we 112562306a36Sopenharmony_ci * see an AifEnConfigChange AIF come through. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) { 112962306a36Sopenharmony_ci device = scsi_device_lookup(dev->scsi_host_ptr, 113062306a36Sopenharmony_ci CONTAINER_TO_CHANNEL(container), 113162306a36Sopenharmony_ci CONTAINER_TO_ID(container), 113262306a36Sopenharmony_ci CONTAINER_TO_LUN(container)); 113362306a36Sopenharmony_ci if (device) { 113462306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = CHANGE; 113562306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; 113662306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = jiffies; 113762306a36Sopenharmony_ci scsi_device_put(device); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* 114362306a36Sopenharmony_ci * If we are waiting on something and this happens to be 114462306a36Sopenharmony_ci * that thing then set the re-configure flag. 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_ci if (container != (u32)-1) { 114762306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci if ((dev->fsa_dev[container].config_waiting_on == 115062306a36Sopenharmony_ci le32_to_cpu(*(__le32 *)aifcmd->data)) && 115162306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) 115262306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 0; 115362306a36Sopenharmony_ci } else for (container = 0; 115462306a36Sopenharmony_ci container < dev->maximum_num_containers; ++container) { 115562306a36Sopenharmony_ci if ((dev->fsa_dev[container].config_waiting_on == 115662306a36Sopenharmony_ci le32_to_cpu(*(__le32 *)aifcmd->data)) && 115762306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) 115862306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 0; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci case AifCmdEventNotify: 116362306a36Sopenharmony_ci switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { 116462306a36Sopenharmony_ci case AifEnBatteryEvent: 116562306a36Sopenharmony_ci dev->cache_protected = 116662306a36Sopenharmony_ci (((__le32 *)aifcmd->data)[1] == cpu_to_le32(3)); 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci /* 116962306a36Sopenharmony_ci * Add an Array. 117062306a36Sopenharmony_ci */ 117162306a36Sopenharmony_ci case AifEnAddContainer: 117262306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 117362306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = ADD; 117662306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 117762306a36Sopenharmony_ci AifEnConfigChange; 117862306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = jiffies; 117962306a36Sopenharmony_ci break; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* 118262306a36Sopenharmony_ci * Delete an Array. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci case AifEnDeleteContainer: 118562306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 118662306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = DELETE; 118962306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 119062306a36Sopenharmony_ci AifEnConfigChange; 119162306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = jiffies; 119262306a36Sopenharmony_ci break; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* 119562306a36Sopenharmony_ci * Container change detected. If we currently are not 119662306a36Sopenharmony_ci * waiting on something else, setup to wait on a Config Change. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci case AifEnContainerChange: 119962306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 120062306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci if (dev->fsa_dev[container].config_waiting_on && 120362306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) 120462306a36Sopenharmony_ci break; 120562306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = CHANGE; 120662306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 120762306a36Sopenharmony_ci AifEnConfigChange; 120862306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = jiffies; 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci case AifEnConfigChange: 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci case AifEnAddJBOD: 121562306a36Sopenharmony_ci case AifEnDeleteJBOD: 121662306a36Sopenharmony_ci container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); 121762306a36Sopenharmony_ci if ((container >> 28)) { 121862306a36Sopenharmony_ci container = (u32)-1; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci channel = (container >> 24) & 0xF; 122262306a36Sopenharmony_ci if (channel >= dev->maximum_num_channels) { 122362306a36Sopenharmony_ci container = (u32)-1; 122462306a36Sopenharmony_ci break; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci id = container & 0xFFFF; 122762306a36Sopenharmony_ci if (id >= dev->maximum_num_physicals) { 122862306a36Sopenharmony_ci container = (u32)-1; 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci lun = (container >> 16) & 0xFF; 123262306a36Sopenharmony_ci container = (u32)-1; 123362306a36Sopenharmony_ci channel = aac_phys_to_logical(channel); 123462306a36Sopenharmony_ci device_config_needed = 123562306a36Sopenharmony_ci (((__le32 *)aifcmd->data)[0] == 123662306a36Sopenharmony_ci cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE; 123762306a36Sopenharmony_ci if (device_config_needed == ADD) { 123862306a36Sopenharmony_ci device = scsi_device_lookup(dev->scsi_host_ptr, 123962306a36Sopenharmony_ci channel, 124062306a36Sopenharmony_ci id, 124162306a36Sopenharmony_ci lun); 124262306a36Sopenharmony_ci if (device) { 124362306a36Sopenharmony_ci scsi_remove_device(device); 124462306a36Sopenharmony_ci scsi_device_put(device); 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci case AifEnEnclosureManagement: 125062306a36Sopenharmony_ci /* 125162306a36Sopenharmony_ci * If in JBOD mode, automatic exposure of new 125262306a36Sopenharmony_ci * physical target to be suppressed until configured. 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_ci if (dev->jbod) 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) { 125762306a36Sopenharmony_ci case EM_DRIVE_INSERTION: 125862306a36Sopenharmony_ci case EM_DRIVE_REMOVAL: 125962306a36Sopenharmony_ci case EM_SES_DRIVE_INSERTION: 126062306a36Sopenharmony_ci case EM_SES_DRIVE_REMOVAL: 126162306a36Sopenharmony_ci container = le32_to_cpu( 126262306a36Sopenharmony_ci ((__le32 *)aifcmd->data)[2]); 126362306a36Sopenharmony_ci if ((container >> 28)) { 126462306a36Sopenharmony_ci container = (u32)-1; 126562306a36Sopenharmony_ci break; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci channel = (container >> 24) & 0xF; 126862306a36Sopenharmony_ci if (channel >= dev->maximum_num_channels) { 126962306a36Sopenharmony_ci container = (u32)-1; 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci id = container & 0xFFFF; 127362306a36Sopenharmony_ci lun = (container >> 16) & 0xFF; 127462306a36Sopenharmony_ci container = (u32)-1; 127562306a36Sopenharmony_ci if (id >= dev->maximum_num_physicals) { 127662306a36Sopenharmony_ci /* legacy dev_t ? */ 127762306a36Sopenharmony_ci if ((0x2000 <= id) || lun || channel || 127862306a36Sopenharmony_ci ((channel = (id >> 7) & 0x3F) >= 127962306a36Sopenharmony_ci dev->maximum_num_channels)) 128062306a36Sopenharmony_ci break; 128162306a36Sopenharmony_ci lun = (id >> 4) & 7; 128262306a36Sopenharmony_ci id &= 0xF; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci channel = aac_phys_to_logical(channel); 128562306a36Sopenharmony_ci device_config_needed = 128662306a36Sopenharmony_ci ((((__le32 *)aifcmd->data)[3] 128762306a36Sopenharmony_ci == cpu_to_le32(EM_DRIVE_INSERTION)) || 128862306a36Sopenharmony_ci (((__le32 *)aifcmd->data)[3] 128962306a36Sopenharmony_ci == cpu_to_le32(EM_SES_DRIVE_INSERTION))) ? 129062306a36Sopenharmony_ci ADD : DELETE; 129162306a36Sopenharmony_ci break; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci case AifBuManagerEvent: 129562306a36Sopenharmony_ci aac_handle_aif_bu(dev, aifcmd); 129662306a36Sopenharmony_ci break; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* 130062306a36Sopenharmony_ci * If we are waiting on something and this happens to be 130162306a36Sopenharmony_ci * that thing then set the re-configure flag. 130262306a36Sopenharmony_ci */ 130362306a36Sopenharmony_ci if (container != (u32)-1) { 130462306a36Sopenharmony_ci if (container >= dev->maximum_num_containers) 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci if ((dev->fsa_dev[container].config_waiting_on == 130762306a36Sopenharmony_ci le32_to_cpu(*(__le32 *)aifcmd->data)) && 130862306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) 130962306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 0; 131062306a36Sopenharmony_ci } else for (container = 0; 131162306a36Sopenharmony_ci container < dev->maximum_num_containers; ++container) { 131262306a36Sopenharmony_ci if ((dev->fsa_dev[container].config_waiting_on == 131362306a36Sopenharmony_ci le32_to_cpu(*(__le32 *)aifcmd->data)) && 131462306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) 131562306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 0; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci break; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci case AifCmdJobProgress: 132062306a36Sopenharmony_ci /* 132162306a36Sopenharmony_ci * These are job progress AIF's. When a Clear is being 132262306a36Sopenharmony_ci * done on a container it is initially created then hidden from 132362306a36Sopenharmony_ci * the OS. When the clear completes we don't get a config 132462306a36Sopenharmony_ci * change so we monitor the job status complete on a clear then 132562306a36Sopenharmony_ci * wait for a container change. 132662306a36Sopenharmony_ci */ 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && 132962306a36Sopenharmony_ci (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] || 133062306a36Sopenharmony_ci ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) { 133162306a36Sopenharmony_ci for (container = 0; 133262306a36Sopenharmony_ci container < dev->maximum_num_containers; 133362306a36Sopenharmony_ci ++container) { 133462306a36Sopenharmony_ci /* 133562306a36Sopenharmony_ci * Stomp on all config sequencing for all 133662306a36Sopenharmony_ci * containers? 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 133962306a36Sopenharmony_ci AifEnContainerChange; 134062306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = ADD; 134162306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = 134262306a36Sopenharmony_ci jiffies; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && 134662306a36Sopenharmony_ci ((__le32 *)aifcmd->data)[6] == 0 && 134762306a36Sopenharmony_ci ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) { 134862306a36Sopenharmony_ci for (container = 0; 134962306a36Sopenharmony_ci container < dev->maximum_num_containers; 135062306a36Sopenharmony_ci ++container) { 135162306a36Sopenharmony_ci /* 135262306a36Sopenharmony_ci * Stomp on all config sequencing for all 135362306a36Sopenharmony_ci * containers? 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_on = 135662306a36Sopenharmony_ci AifEnContainerChange; 135762306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = DELETE; 135862306a36Sopenharmony_ci dev->fsa_dev[container].config_waiting_stamp = 135962306a36Sopenharmony_ci jiffies; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci break; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci container = 0; 136662306a36Sopenharmony_ciretry_next: 136762306a36Sopenharmony_ci if (device_config_needed == NOTHING) { 136862306a36Sopenharmony_ci for (; container < dev->maximum_num_containers; ++container) { 136962306a36Sopenharmony_ci if ((dev->fsa_dev[container].config_waiting_on == 0) && 137062306a36Sopenharmony_ci (dev->fsa_dev[container].config_needed != NOTHING) && 137162306a36Sopenharmony_ci time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) { 137262306a36Sopenharmony_ci device_config_needed = 137362306a36Sopenharmony_ci dev->fsa_dev[container].config_needed; 137462306a36Sopenharmony_ci dev->fsa_dev[container].config_needed = NOTHING; 137562306a36Sopenharmony_ci channel = CONTAINER_TO_CHANNEL(container); 137662306a36Sopenharmony_ci id = CONTAINER_TO_ID(container); 137762306a36Sopenharmony_ci lun = CONTAINER_TO_LUN(container); 137862306a36Sopenharmony_ci break; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci if (device_config_needed == NOTHING) 138362306a36Sopenharmony_ci return; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* 138662306a36Sopenharmony_ci * If we decided that a re-configuration needs to be done, 138762306a36Sopenharmony_ci * schedule it here on the way out the door, please close the door 138862306a36Sopenharmony_ci * behind you. 138962306a36Sopenharmony_ci */ 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci /* 139262306a36Sopenharmony_ci * Find the scsi_device associated with the SCSI address, 139362306a36Sopenharmony_ci * and mark it as changed, invalidating the cache. This deals 139462306a36Sopenharmony_ci * with changes to existing device IDs. 139562306a36Sopenharmony_ci */ 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (!dev || !dev->scsi_host_ptr) 139862306a36Sopenharmony_ci return; 139962306a36Sopenharmony_ci /* 140062306a36Sopenharmony_ci * force reload of disk info via aac_probe_container 140162306a36Sopenharmony_ci */ 140262306a36Sopenharmony_ci if ((channel == CONTAINER_CHANNEL) && 140362306a36Sopenharmony_ci (device_config_needed != NOTHING)) { 140462306a36Sopenharmony_ci if (dev->fsa_dev[container].valid == 1) 140562306a36Sopenharmony_ci dev->fsa_dev[container].valid = 2; 140662306a36Sopenharmony_ci aac_probe_container(dev, container); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun); 140962306a36Sopenharmony_ci if (device) { 141062306a36Sopenharmony_ci switch (device_config_needed) { 141162306a36Sopenharmony_ci case DELETE: 141262306a36Sopenharmony_ci#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) 141362306a36Sopenharmony_ci scsi_remove_device(device); 141462306a36Sopenharmony_ci#else 141562306a36Sopenharmony_ci if (scsi_device_online(device)) { 141662306a36Sopenharmony_ci scsi_device_set_state(device, SDEV_OFFLINE); 141762306a36Sopenharmony_ci sdev_printk(KERN_INFO, device, 141862306a36Sopenharmony_ci "Device offlined - %s\n", 141962306a36Sopenharmony_ci (channel == CONTAINER_CHANNEL) ? 142062306a36Sopenharmony_ci "array deleted" : 142162306a36Sopenharmony_ci "enclosure services event"); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci#endif 142462306a36Sopenharmony_ci break; 142562306a36Sopenharmony_ci case ADD: 142662306a36Sopenharmony_ci if (!scsi_device_online(device)) { 142762306a36Sopenharmony_ci sdev_printk(KERN_INFO, device, 142862306a36Sopenharmony_ci "Device online - %s\n", 142962306a36Sopenharmony_ci (channel == CONTAINER_CHANNEL) ? 143062306a36Sopenharmony_ci "array created" : 143162306a36Sopenharmony_ci "enclosure services event"); 143262306a36Sopenharmony_ci scsi_device_set_state(device, SDEV_RUNNING); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci fallthrough; 143562306a36Sopenharmony_ci case CHANGE: 143662306a36Sopenharmony_ci if ((channel == CONTAINER_CHANNEL) 143762306a36Sopenharmony_ci && (!dev->fsa_dev[container].valid)) { 143862306a36Sopenharmony_ci#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) 143962306a36Sopenharmony_ci scsi_remove_device(device); 144062306a36Sopenharmony_ci#else 144162306a36Sopenharmony_ci if (!scsi_device_online(device)) 144262306a36Sopenharmony_ci break; 144362306a36Sopenharmony_ci scsi_device_set_state(device, SDEV_OFFLINE); 144462306a36Sopenharmony_ci sdev_printk(KERN_INFO, device, 144562306a36Sopenharmony_ci "Device offlined - %s\n", 144662306a36Sopenharmony_ci "array failed"); 144762306a36Sopenharmony_ci#endif 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci scsi_rescan_device(device); 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci default: 145462306a36Sopenharmony_ci break; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci scsi_device_put(device); 145762306a36Sopenharmony_ci device_config_needed = NOTHING; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci if (device_config_needed == ADD) 146062306a36Sopenharmony_ci scsi_add_device(dev->scsi_host_ptr, channel, id, lun); 146162306a36Sopenharmony_ci if (channel == CONTAINER_CHANNEL) { 146262306a36Sopenharmony_ci container++; 146362306a36Sopenharmony_ci device_config_needed = NOTHING; 146462306a36Sopenharmony_ci goto retry_next; 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic void aac_schedule_bus_scan(struct aac_dev *aac) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci if (aac->sa_firmware) 147162306a36Sopenharmony_ci aac_schedule_safw_scan_worker(aac); 147262306a36Sopenharmony_ci else 147362306a36Sopenharmony_ci aac_schedule_src_reinit_aif_worker(aac); 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cistatic int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci int index, quirks; 147962306a36Sopenharmony_ci int retval; 148062306a36Sopenharmony_ci struct Scsi_Host *host = aac->scsi_host_ptr; 148162306a36Sopenharmony_ci int jafo = 0; 148262306a36Sopenharmony_ci int bled; 148362306a36Sopenharmony_ci u64 dmamask; 148462306a36Sopenharmony_ci int num_of_fibs = 0; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* 148762306a36Sopenharmony_ci * Assumptions: 148862306a36Sopenharmony_ci * - host is locked, unless called by the aacraid thread. 148962306a36Sopenharmony_ci * (a matter of convenience, due to legacy issues surrounding 149062306a36Sopenharmony_ci * eh_host_adapter_reset). 149162306a36Sopenharmony_ci * - in_reset is asserted, so no new i/o is getting to the 149262306a36Sopenharmony_ci * card. 149362306a36Sopenharmony_ci * - The card is dead, or will be very shortly ;-/ so no new 149462306a36Sopenharmony_ci * commands are completing in the interrupt service. 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_ci aac_adapter_disable_int(aac); 149762306a36Sopenharmony_ci if (aac->thread && aac->thread->pid != current->pid) { 149862306a36Sopenharmony_ci spin_unlock_irq(host->host_lock); 149962306a36Sopenharmony_ci kthread_stop(aac->thread); 150062306a36Sopenharmony_ci aac->thread = NULL; 150162306a36Sopenharmony_ci jafo = 1; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* 150562306a36Sopenharmony_ci * If a positive health, means in a known DEAD PANIC 150662306a36Sopenharmony_ci * state and the adapter could be reset to `try again'. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci bled = forced ? 0 : aac_adapter_check_health(aac); 150962306a36Sopenharmony_ci retval = aac_adapter_restart(aac, bled, reset_type); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (retval) 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* 151562306a36Sopenharmony_ci * Loop through the fibs, close the synchronous FIBS 151662306a36Sopenharmony_ci */ 151762306a36Sopenharmony_ci retval = 1; 151862306a36Sopenharmony_ci num_of_fibs = aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB; 151962306a36Sopenharmony_ci for (index = 0; index < num_of_fibs; index++) { 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci struct fib *fib = &aac->fibs[index]; 152262306a36Sopenharmony_ci __le32 XferState = fib->hw_fib_va->header.XferState; 152362306a36Sopenharmony_ci bool is_response_expected = false; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (!(XferState & cpu_to_le32(NoResponseExpected | Async)) && 152662306a36Sopenharmony_ci (XferState & cpu_to_le32(ResponseExpected))) 152762306a36Sopenharmony_ci is_response_expected = true; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (is_response_expected 153062306a36Sopenharmony_ci || fib->flags & FIB_CONTEXT_FLAG_WAIT) { 153162306a36Sopenharmony_ci unsigned long flagv; 153262306a36Sopenharmony_ci spin_lock_irqsave(&fib->event_lock, flagv); 153362306a36Sopenharmony_ci complete(&fib->event_wait); 153462306a36Sopenharmony_ci spin_unlock_irqrestore(&fib->event_lock, flagv); 153562306a36Sopenharmony_ci schedule(); 153662306a36Sopenharmony_ci retval = 0; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci /* Give some extra time for ioctls to complete. */ 154062306a36Sopenharmony_ci if (retval == 0) 154162306a36Sopenharmony_ci ssleep(2); 154262306a36Sopenharmony_ci index = aac->cardtype; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci /* 154562306a36Sopenharmony_ci * Re-initialize the adapter, first free resources, then carefully 154662306a36Sopenharmony_ci * apply the initialization sequence to come back again. Only risk 154762306a36Sopenharmony_ci * is a change in Firmware dropping cache, it is assumed the caller 154862306a36Sopenharmony_ci * will ensure that i/o is queisced and the card is flushed in that 154962306a36Sopenharmony_ci * case. 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ci aac_free_irq(aac); 155262306a36Sopenharmony_ci aac_fib_map_free(aac); 155362306a36Sopenharmony_ci dma_free_coherent(&aac->pdev->dev, aac->comm_size, aac->comm_addr, 155462306a36Sopenharmony_ci aac->comm_phys); 155562306a36Sopenharmony_ci aac_adapter_ioremap(aac, 0); 155662306a36Sopenharmony_ci aac->comm_addr = NULL; 155762306a36Sopenharmony_ci aac->comm_phys = 0; 155862306a36Sopenharmony_ci kfree(aac->queues); 155962306a36Sopenharmony_ci aac->queues = NULL; 156062306a36Sopenharmony_ci kfree(aac->fsa_dev); 156162306a36Sopenharmony_ci aac->fsa_dev = NULL; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci dmamask = DMA_BIT_MASK(32); 156462306a36Sopenharmony_ci quirks = aac_get_driver_ident(index)->quirks; 156562306a36Sopenharmony_ci if (quirks & AAC_QUIRK_31BIT) 156662306a36Sopenharmony_ci retval = dma_set_mask(&aac->pdev->dev, dmamask); 156762306a36Sopenharmony_ci else if (!(quirks & AAC_QUIRK_SRC)) 156862306a36Sopenharmony_ci retval = dma_set_mask(&aac->pdev->dev, dmamask); 156962306a36Sopenharmony_ci else 157062306a36Sopenharmony_ci retval = dma_set_coherent_mask(&aac->pdev->dev, dmamask); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (quirks & AAC_QUIRK_31BIT && !retval) { 157362306a36Sopenharmony_ci dmamask = DMA_BIT_MASK(31); 157462306a36Sopenharmony_ci retval = dma_set_coherent_mask(&aac->pdev->dev, dmamask); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (retval) 157862306a36Sopenharmony_ci goto out; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if ((retval = (*(aac_get_driver_ident(index)->init))(aac))) 158162306a36Sopenharmony_ci goto out; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if (jafo) { 158462306a36Sopenharmony_ci aac->thread = kthread_run(aac_command_thread, aac, "%s", 158562306a36Sopenharmony_ci aac->name); 158662306a36Sopenharmony_ci if (IS_ERR(aac->thread)) { 158762306a36Sopenharmony_ci retval = PTR_ERR(aac->thread); 158862306a36Sopenharmony_ci aac->thread = NULL; 158962306a36Sopenharmony_ci goto out; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci (void)aac_get_adapter_info(aac); 159362306a36Sopenharmony_ci if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) { 159462306a36Sopenharmony_ci host->sg_tablesize = 34; 159562306a36Sopenharmony_ci host->max_sectors = (host->sg_tablesize * 8) + 112; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) { 159862306a36Sopenharmony_ci host->sg_tablesize = 17; 159962306a36Sopenharmony_ci host->max_sectors = (host->sg_tablesize * 8) + 112; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci aac_get_config_status(aac, 1); 160262306a36Sopenharmony_ci aac_get_containers(aac); 160362306a36Sopenharmony_ci /* 160462306a36Sopenharmony_ci * This is where the assumption that the Adapter is quiesced 160562306a36Sopenharmony_ci * is important. 160662306a36Sopenharmony_ci */ 160762306a36Sopenharmony_ci scsi_host_complete_all_commands(host, DID_RESET); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci retval = 0; 161062306a36Sopenharmony_ciout: 161162306a36Sopenharmony_ci aac->in_reset = 0; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* 161462306a36Sopenharmony_ci * Issue bus rescan to catch any configuration that might have 161562306a36Sopenharmony_ci * occurred 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci if (!retval && !is_kdump_kernel()) { 161862306a36Sopenharmony_ci dev_info(&aac->pdev->dev, "Scheduling bus rescan\n"); 161962306a36Sopenharmony_ci aac_schedule_bus_scan(aac); 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (jafo) { 162362306a36Sopenharmony_ci spin_lock_irq(host->host_lock); 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci return retval; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ciint aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci unsigned long flagv = 0; 163162306a36Sopenharmony_ci int retval, unblock_retval; 163262306a36Sopenharmony_ci struct Scsi_Host *host = aac->scsi_host_ptr; 163362306a36Sopenharmony_ci int bled; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) 163662306a36Sopenharmony_ci return -EBUSY; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (aac->in_reset) { 163962306a36Sopenharmony_ci spin_unlock_irqrestore(&aac->fib_lock, flagv); 164062306a36Sopenharmony_ci return -EBUSY; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci aac->in_reset = 1; 164362306a36Sopenharmony_ci spin_unlock_irqrestore(&aac->fib_lock, flagv); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* 164662306a36Sopenharmony_ci * Wait for all commands to complete to this specific 164762306a36Sopenharmony_ci * target (block maximum 60 seconds). Although not necessary, 164862306a36Sopenharmony_ci * it does make us a good storage citizen. 164962306a36Sopenharmony_ci */ 165062306a36Sopenharmony_ci scsi_host_block(host); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* Quiesce build, flush cache, write through mode */ 165362306a36Sopenharmony_ci if (forced < 2) 165462306a36Sopenharmony_ci aac_send_shutdown(aac); 165562306a36Sopenharmony_ci spin_lock_irqsave(host->host_lock, flagv); 165662306a36Sopenharmony_ci bled = forced ? forced : 165762306a36Sopenharmony_ci (aac_check_reset != 0 && aac_check_reset != 1); 165862306a36Sopenharmony_ci retval = _aac_reset_adapter(aac, bled, reset_type); 165962306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flagv); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci unblock_retval = scsi_host_unblock(host, SDEV_RUNNING); 166262306a36Sopenharmony_ci if (!retval) 166362306a36Sopenharmony_ci retval = unblock_retval; 166462306a36Sopenharmony_ci if ((forced < 2) && (retval == -ENODEV)) { 166562306a36Sopenharmony_ci /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */ 166662306a36Sopenharmony_ci struct fib * fibctx = aac_fib_alloc(aac); 166762306a36Sopenharmony_ci if (fibctx) { 166862306a36Sopenharmony_ci struct aac_pause *cmd; 166962306a36Sopenharmony_ci int status; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci aac_fib_init(fibctx); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci cmd = (struct aac_pause *) fib_data(fibctx); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci cmd->command = cpu_to_le32(VM_ContainerConfig); 167662306a36Sopenharmony_ci cmd->type = cpu_to_le32(CT_PAUSE_IO); 167762306a36Sopenharmony_ci cmd->timeout = cpu_to_le32(1); 167862306a36Sopenharmony_ci cmd->min = cpu_to_le32(1); 167962306a36Sopenharmony_ci cmd->noRescan = cpu_to_le32(1); 168062306a36Sopenharmony_ci cmd->count = cpu_to_le32(0); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci status = aac_fib_send(ContainerCommand, 168362306a36Sopenharmony_ci fibctx, 168462306a36Sopenharmony_ci sizeof(struct aac_pause), 168562306a36Sopenharmony_ci FsaNormal, 168662306a36Sopenharmony_ci -2 /* Timeout silently */, 1, 168762306a36Sopenharmony_ci NULL, NULL); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (status >= 0) 169062306a36Sopenharmony_ci aac_fib_complete(fibctx); 169162306a36Sopenharmony_ci /* FIB should be freed only after getting 169262306a36Sopenharmony_ci * the response from the F/W */ 169362306a36Sopenharmony_ci if (status != -ERESTARTSYS) 169462306a36Sopenharmony_ci aac_fib_free(fibctx); 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci return retval; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ciint aac_check_health(struct aac_dev * aac) 170262306a36Sopenharmony_ci{ 170362306a36Sopenharmony_ci int BlinkLED; 170462306a36Sopenharmony_ci unsigned long time_now, flagv = 0; 170562306a36Sopenharmony_ci struct list_head * entry; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* Extending the scope of fib_lock slightly to protect aac->in_reset */ 170862306a36Sopenharmony_ci if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) 170962306a36Sopenharmony_ci return 0; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) { 171262306a36Sopenharmony_ci spin_unlock_irqrestore(&aac->fib_lock, flagv); 171362306a36Sopenharmony_ci return 0; /* OK */ 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci aac->in_reset = 1; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci /* Fake up an AIF: 171962306a36Sopenharmony_ci * aac_aifcmd.command = AifCmdEventNotify = 1 172062306a36Sopenharmony_ci * aac_aifcmd.seqnum = 0xFFFFFFFF 172162306a36Sopenharmony_ci * aac_aifcmd.data[0] = AifEnExpEvent = 23 172262306a36Sopenharmony_ci * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3 172362306a36Sopenharmony_ci * aac.aifcmd.data[2] = AifHighPriority = 3 172462306a36Sopenharmony_ci * aac.aifcmd.data[3] = BlinkLED 172562306a36Sopenharmony_ci */ 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci time_now = jiffies/HZ; 172862306a36Sopenharmony_ci entry = aac->fib_list.next; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci /* 173162306a36Sopenharmony_ci * For each Context that is on the 173262306a36Sopenharmony_ci * fibctxList, make a copy of the 173362306a36Sopenharmony_ci * fib, and then set the event to wake up the 173462306a36Sopenharmony_ci * thread that is waiting for it. 173562306a36Sopenharmony_ci */ 173662306a36Sopenharmony_ci while (entry != &aac->fib_list) { 173762306a36Sopenharmony_ci /* 173862306a36Sopenharmony_ci * Extract the fibctx 173962306a36Sopenharmony_ci */ 174062306a36Sopenharmony_ci struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next); 174162306a36Sopenharmony_ci struct hw_fib * hw_fib; 174262306a36Sopenharmony_ci struct fib * fib; 174362306a36Sopenharmony_ci /* 174462306a36Sopenharmony_ci * Check if the queue is getting 174562306a36Sopenharmony_ci * backlogged 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_ci if (fibctx->count > 20) { 174862306a36Sopenharmony_ci /* 174962306a36Sopenharmony_ci * It's *not* jiffies folks, 175062306a36Sopenharmony_ci * but jiffies / HZ, so do not 175162306a36Sopenharmony_ci * panic ... 175262306a36Sopenharmony_ci */ 175362306a36Sopenharmony_ci u32 time_last = fibctx->jiffies; 175462306a36Sopenharmony_ci /* 175562306a36Sopenharmony_ci * Has it been > 2 minutes 175662306a36Sopenharmony_ci * since the last read off 175762306a36Sopenharmony_ci * the queue? 175862306a36Sopenharmony_ci */ 175962306a36Sopenharmony_ci if ((time_now - time_last) > aif_timeout) { 176062306a36Sopenharmony_ci entry = entry->next; 176162306a36Sopenharmony_ci aac_close_fib_context(aac, fibctx); 176262306a36Sopenharmony_ci continue; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci /* 176662306a36Sopenharmony_ci * Warning: no sleep allowed while 176762306a36Sopenharmony_ci * holding spinlock 176862306a36Sopenharmony_ci */ 176962306a36Sopenharmony_ci hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC); 177062306a36Sopenharmony_ci fib = kzalloc(sizeof(struct fib), GFP_ATOMIC); 177162306a36Sopenharmony_ci if (fib && hw_fib) { 177262306a36Sopenharmony_ci struct aac_aifcmd * aif; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci fib->hw_fib_va = hw_fib; 177562306a36Sopenharmony_ci fib->dev = aac; 177662306a36Sopenharmony_ci aac_fib_init(fib); 177762306a36Sopenharmony_ci fib->type = FSAFS_NTC_FIB_CONTEXT; 177862306a36Sopenharmony_ci fib->size = sizeof (struct fib); 177962306a36Sopenharmony_ci fib->data = hw_fib->data; 178062306a36Sopenharmony_ci aif = (struct aac_aifcmd *)hw_fib->data; 178162306a36Sopenharmony_ci aif->command = cpu_to_le32(AifCmdEventNotify); 178262306a36Sopenharmony_ci aif->seqnum = cpu_to_le32(0xFFFFFFFF); 178362306a36Sopenharmony_ci ((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent); 178462306a36Sopenharmony_ci ((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic); 178562306a36Sopenharmony_ci ((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority); 178662306a36Sopenharmony_ci ((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci /* 178962306a36Sopenharmony_ci * Put the FIB onto the 179062306a36Sopenharmony_ci * fibctx's fibs 179162306a36Sopenharmony_ci */ 179262306a36Sopenharmony_ci list_add_tail(&fib->fiblink, &fibctx->fib_list); 179362306a36Sopenharmony_ci fibctx->count++; 179462306a36Sopenharmony_ci /* 179562306a36Sopenharmony_ci * Set the event to wake up the 179662306a36Sopenharmony_ci * thread that will waiting. 179762306a36Sopenharmony_ci */ 179862306a36Sopenharmony_ci complete(&fibctx->completion); 179962306a36Sopenharmony_ci } else { 180062306a36Sopenharmony_ci printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); 180162306a36Sopenharmony_ci kfree(fib); 180262306a36Sopenharmony_ci kfree(hw_fib); 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci entry = entry->next; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci spin_unlock_irqrestore(&aac->fib_lock, flagv); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (BlinkLED < 0) { 181062306a36Sopenharmony_ci printk(KERN_ERR "%s: Host adapter is dead (or got a PCI error) %d\n", 181162306a36Sopenharmony_ci aac->name, BlinkLED); 181262306a36Sopenharmony_ci goto out; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ciout: 181862306a36Sopenharmony_ci aac->in_reset = 0; 181962306a36Sopenharmony_ci return BlinkLED; 182062306a36Sopenharmony_ci} 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_cistatic inline int is_safw_raid_volume(struct aac_dev *aac, int bus, int target) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci return bus == CONTAINER_CHANNEL && target < aac->maximum_num_containers; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic struct scsi_device *aac_lookup_safw_scsi_device(struct aac_dev *dev, 182862306a36Sopenharmony_ci int bus, 182962306a36Sopenharmony_ci int target) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci if (bus != CONTAINER_CHANNEL) 183262306a36Sopenharmony_ci bus = aac_phys_to_logical(bus); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci return scsi_device_lookup(dev->scsi_host_ptr, bus, target, 0); 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic int aac_add_safw_device(struct aac_dev *dev, int bus, int target) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci if (bus != CONTAINER_CHANNEL) 184062306a36Sopenharmony_ci bus = aac_phys_to_logical(bus); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci return scsi_add_device(dev->scsi_host_ptr, bus, target, 0); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_cistatic void aac_put_safw_scsi_device(struct scsi_device *sdev) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci if (sdev) 184862306a36Sopenharmony_ci scsi_device_put(sdev); 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_cistatic void aac_remove_safw_device(struct aac_dev *dev, int bus, int target) 185262306a36Sopenharmony_ci{ 185362306a36Sopenharmony_ci struct scsi_device *sdev; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci sdev = aac_lookup_safw_scsi_device(dev, bus, target); 185662306a36Sopenharmony_ci scsi_remove_device(sdev); 185762306a36Sopenharmony_ci aac_put_safw_scsi_device(sdev); 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_cistatic inline int aac_is_safw_scan_count_equal(struct aac_dev *dev, 186162306a36Sopenharmony_ci int bus, int target) 186262306a36Sopenharmony_ci{ 186362306a36Sopenharmony_ci return dev->hba_map[bus][target].scan_counter == dev->scan_counter; 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_cistatic int aac_is_safw_target_valid(struct aac_dev *dev, int bus, int target) 186762306a36Sopenharmony_ci{ 186862306a36Sopenharmony_ci if (is_safw_raid_volume(dev, bus, target)) 186962306a36Sopenharmony_ci return dev->fsa_dev[target].valid; 187062306a36Sopenharmony_ci else 187162306a36Sopenharmony_ci return aac_is_safw_scan_count_equal(dev, bus, target); 187262306a36Sopenharmony_ci} 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_cistatic int aac_is_safw_device_exposed(struct aac_dev *dev, int bus, int target) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci int is_exposed = 0; 187762306a36Sopenharmony_ci struct scsi_device *sdev; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci sdev = aac_lookup_safw_scsi_device(dev, bus, target); 188062306a36Sopenharmony_ci if (sdev) 188162306a36Sopenharmony_ci is_exposed = 1; 188262306a36Sopenharmony_ci aac_put_safw_scsi_device(sdev); 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci return is_exposed; 188562306a36Sopenharmony_ci} 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_cistatic int aac_update_safw_host_devices(struct aac_dev *dev) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci int i; 189062306a36Sopenharmony_ci int bus; 189162306a36Sopenharmony_ci int target; 189262306a36Sopenharmony_ci int is_exposed = 0; 189362306a36Sopenharmony_ci int rcode = 0; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci rcode = aac_setup_safw_adapter(dev); 189662306a36Sopenharmony_ci if (unlikely(rcode < 0)) { 189762306a36Sopenharmony_ci goto out; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci for (i = 0; i < AAC_BUS_TARGET_LOOP; i++) { 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci bus = get_bus_number(i); 190362306a36Sopenharmony_ci target = get_target_number(i); 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci is_exposed = aac_is_safw_device_exposed(dev, bus, target); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if (aac_is_safw_target_valid(dev, bus, target) && !is_exposed) 190862306a36Sopenharmony_ci aac_add_safw_device(dev, bus, target); 190962306a36Sopenharmony_ci else if (!aac_is_safw_target_valid(dev, bus, target) && 191062306a36Sopenharmony_ci is_exposed) 191162306a36Sopenharmony_ci aac_remove_safw_device(dev, bus, target); 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ciout: 191462306a36Sopenharmony_ci return rcode; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic int aac_scan_safw_host(struct aac_dev *dev) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci int rcode = 0; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci rcode = aac_update_safw_host_devices(dev); 192262306a36Sopenharmony_ci if (rcode) 192362306a36Sopenharmony_ci aac_schedule_safw_scan_worker(dev); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci return rcode; 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ciint aac_scan_host(struct aac_dev *dev) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci int rcode = 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci mutex_lock(&dev->scan_mutex); 193362306a36Sopenharmony_ci if (dev->sa_firmware) 193462306a36Sopenharmony_ci rcode = aac_scan_safw_host(dev); 193562306a36Sopenharmony_ci else 193662306a36Sopenharmony_ci scsi_scan_host(dev->scsi_host_ptr); 193762306a36Sopenharmony_ci mutex_unlock(&dev->scan_mutex); 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci return rcode; 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_civoid aac_src_reinit_aif_worker(struct work_struct *work) 194362306a36Sopenharmony_ci{ 194462306a36Sopenharmony_ci struct aac_dev *dev = container_of(to_delayed_work(work), 194562306a36Sopenharmony_ci struct aac_dev, src_reinit_aif_worker); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci wait_event(dev->scsi_host_ptr->host_wait, 194862306a36Sopenharmony_ci !scsi_host_in_recovery(dev->scsi_host_ptr)); 194962306a36Sopenharmony_ci aac_reinit_aif(dev, dev->cardtype); 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci/** 195362306a36Sopenharmony_ci * aac_handle_sa_aif - Handle a message from the firmware 195462306a36Sopenharmony_ci * @dev: Which adapter this fib is from 195562306a36Sopenharmony_ci * @fibptr: Pointer to fibptr from adapter 195662306a36Sopenharmony_ci * 195762306a36Sopenharmony_ci * This routine handles a driver notify fib from the adapter and 195862306a36Sopenharmony_ci * dispatches it to the appropriate routine for handling. 195962306a36Sopenharmony_ci */ 196062306a36Sopenharmony_cistatic void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr) 196162306a36Sopenharmony_ci{ 196262306a36Sopenharmony_ci int i; 196362306a36Sopenharmony_ci u32 events = 0; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if (fibptr->hbacmd_size & SA_AIF_HOTPLUG) 196662306a36Sopenharmony_ci events = SA_AIF_HOTPLUG; 196762306a36Sopenharmony_ci else if (fibptr->hbacmd_size & SA_AIF_HARDWARE) 196862306a36Sopenharmony_ci events = SA_AIF_HARDWARE; 196962306a36Sopenharmony_ci else if (fibptr->hbacmd_size & SA_AIF_PDEV_CHANGE) 197062306a36Sopenharmony_ci events = SA_AIF_PDEV_CHANGE; 197162306a36Sopenharmony_ci else if (fibptr->hbacmd_size & SA_AIF_LDEV_CHANGE) 197262306a36Sopenharmony_ci events = SA_AIF_LDEV_CHANGE; 197362306a36Sopenharmony_ci else if (fibptr->hbacmd_size & SA_AIF_BPSTAT_CHANGE) 197462306a36Sopenharmony_ci events = SA_AIF_BPSTAT_CHANGE; 197562306a36Sopenharmony_ci else if (fibptr->hbacmd_size & SA_AIF_BPCFG_CHANGE) 197662306a36Sopenharmony_ci events = SA_AIF_BPCFG_CHANGE; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci switch (events) { 197962306a36Sopenharmony_ci case SA_AIF_HOTPLUG: 198062306a36Sopenharmony_ci case SA_AIF_HARDWARE: 198162306a36Sopenharmony_ci case SA_AIF_PDEV_CHANGE: 198262306a36Sopenharmony_ci case SA_AIF_LDEV_CHANGE: 198362306a36Sopenharmony_ci case SA_AIF_BPCFG_CHANGE: 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci aac_scan_host(dev); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci break; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci case SA_AIF_BPSTAT_CHANGE: 199062306a36Sopenharmony_ci /* currently do nothing */ 199162306a36Sopenharmony_ci break; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci for (i = 1; i <= 10; ++i) { 199562306a36Sopenharmony_ci events = src_readl(dev, MUnit.IDR); 199662306a36Sopenharmony_ci if (events & (1<<23)) { 199762306a36Sopenharmony_ci pr_warn(" AIF not cleared by firmware - %d/%d)\n", 199862306a36Sopenharmony_ci i, 10); 199962306a36Sopenharmony_ci ssleep(1); 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci } 200262306a36Sopenharmony_ci} 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_cistatic int get_fib_count(struct aac_dev *dev) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci unsigned int num = 0; 200762306a36Sopenharmony_ci struct list_head *entry; 200862306a36Sopenharmony_ci unsigned long flagv; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci /* 201162306a36Sopenharmony_ci * Warning: no sleep allowed while 201262306a36Sopenharmony_ci * holding spinlock. We take the estimate 201362306a36Sopenharmony_ci * and pre-allocate a set of fibs outside the 201462306a36Sopenharmony_ci * lock. 201562306a36Sopenharmony_ci */ 201662306a36Sopenharmony_ci num = le32_to_cpu(dev->init->r7.adapter_fibs_size) 201762306a36Sopenharmony_ci / sizeof(struct hw_fib); /* some extra */ 201862306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flagv); 201962306a36Sopenharmony_ci entry = dev->fib_list.next; 202062306a36Sopenharmony_ci while (entry != &dev->fib_list) { 202162306a36Sopenharmony_ci entry = entry->next; 202262306a36Sopenharmony_ci ++num; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flagv); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci return num; 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic int fillup_pools(struct aac_dev *dev, struct hw_fib **hw_fib_pool, 203062306a36Sopenharmony_ci struct fib **fib_pool, 203162306a36Sopenharmony_ci unsigned int num) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci struct hw_fib **hw_fib_p; 203462306a36Sopenharmony_ci struct fib **fib_p; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci hw_fib_p = hw_fib_pool; 203762306a36Sopenharmony_ci fib_p = fib_pool; 203862306a36Sopenharmony_ci while (hw_fib_p < &hw_fib_pool[num]) { 203962306a36Sopenharmony_ci *(hw_fib_p) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL); 204062306a36Sopenharmony_ci if (!(*(hw_fib_p++))) { 204162306a36Sopenharmony_ci --hw_fib_p; 204262306a36Sopenharmony_ci break; 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci *(fib_p) = kmalloc(sizeof(struct fib), GFP_KERNEL); 204662306a36Sopenharmony_ci if (!(*(fib_p++))) { 204762306a36Sopenharmony_ci kfree(*(--hw_fib_p)); 204862306a36Sopenharmony_ci break; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* 205362306a36Sopenharmony_ci * Get the actual number of allocated fibs 205462306a36Sopenharmony_ci */ 205562306a36Sopenharmony_ci num = hw_fib_p - hw_fib_pool; 205662306a36Sopenharmony_ci return num; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic void wakeup_fibctx_threads(struct aac_dev *dev, 206062306a36Sopenharmony_ci struct hw_fib **hw_fib_pool, 206162306a36Sopenharmony_ci struct fib **fib_pool, 206262306a36Sopenharmony_ci struct fib *fib, 206362306a36Sopenharmony_ci struct hw_fib *hw_fib, 206462306a36Sopenharmony_ci unsigned int num) 206562306a36Sopenharmony_ci{ 206662306a36Sopenharmony_ci unsigned long flagv; 206762306a36Sopenharmony_ci struct list_head *entry; 206862306a36Sopenharmony_ci struct hw_fib **hw_fib_p; 206962306a36Sopenharmony_ci struct fib **fib_p; 207062306a36Sopenharmony_ci u32 time_now, time_last; 207162306a36Sopenharmony_ci struct hw_fib *hw_newfib; 207262306a36Sopenharmony_ci struct fib *newfib; 207362306a36Sopenharmony_ci struct aac_fib_context *fibctx; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci time_now = jiffies/HZ; 207662306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flagv); 207762306a36Sopenharmony_ci entry = dev->fib_list.next; 207862306a36Sopenharmony_ci /* 207962306a36Sopenharmony_ci * For each Context that is on the 208062306a36Sopenharmony_ci * fibctxList, make a copy of the 208162306a36Sopenharmony_ci * fib, and then set the event to wake up the 208262306a36Sopenharmony_ci * thread that is waiting for it. 208362306a36Sopenharmony_ci */ 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci hw_fib_p = hw_fib_pool; 208662306a36Sopenharmony_ci fib_p = fib_pool; 208762306a36Sopenharmony_ci while (entry != &dev->fib_list) { 208862306a36Sopenharmony_ci /* 208962306a36Sopenharmony_ci * Extract the fibctx 209062306a36Sopenharmony_ci */ 209162306a36Sopenharmony_ci fibctx = list_entry(entry, struct aac_fib_context, 209262306a36Sopenharmony_ci next); 209362306a36Sopenharmony_ci /* 209462306a36Sopenharmony_ci * Check if the queue is getting 209562306a36Sopenharmony_ci * backlogged 209662306a36Sopenharmony_ci */ 209762306a36Sopenharmony_ci if (fibctx->count > 20) { 209862306a36Sopenharmony_ci /* 209962306a36Sopenharmony_ci * It's *not* jiffies folks, 210062306a36Sopenharmony_ci * but jiffies / HZ so do not 210162306a36Sopenharmony_ci * panic ... 210262306a36Sopenharmony_ci */ 210362306a36Sopenharmony_ci time_last = fibctx->jiffies; 210462306a36Sopenharmony_ci /* 210562306a36Sopenharmony_ci * Has it been > 2 minutes 210662306a36Sopenharmony_ci * since the last read off 210762306a36Sopenharmony_ci * the queue? 210862306a36Sopenharmony_ci */ 210962306a36Sopenharmony_ci if ((time_now - time_last) > aif_timeout) { 211062306a36Sopenharmony_ci entry = entry->next; 211162306a36Sopenharmony_ci aac_close_fib_context(dev, fibctx); 211262306a36Sopenharmony_ci continue; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci /* 211662306a36Sopenharmony_ci * Warning: no sleep allowed while 211762306a36Sopenharmony_ci * holding spinlock 211862306a36Sopenharmony_ci */ 211962306a36Sopenharmony_ci if (hw_fib_p >= &hw_fib_pool[num]) { 212062306a36Sopenharmony_ci pr_warn("aifd: didn't allocate NewFib\n"); 212162306a36Sopenharmony_ci entry = entry->next; 212262306a36Sopenharmony_ci continue; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci hw_newfib = *hw_fib_p; 212662306a36Sopenharmony_ci *(hw_fib_p++) = NULL; 212762306a36Sopenharmony_ci newfib = *fib_p; 212862306a36Sopenharmony_ci *(fib_p++) = NULL; 212962306a36Sopenharmony_ci /* 213062306a36Sopenharmony_ci * Make the copy of the FIB 213162306a36Sopenharmony_ci */ 213262306a36Sopenharmony_ci memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib)); 213362306a36Sopenharmony_ci memcpy(newfib, fib, sizeof(struct fib)); 213462306a36Sopenharmony_ci newfib->hw_fib_va = hw_newfib; 213562306a36Sopenharmony_ci /* 213662306a36Sopenharmony_ci * Put the FIB onto the 213762306a36Sopenharmony_ci * fibctx's fibs 213862306a36Sopenharmony_ci */ 213962306a36Sopenharmony_ci list_add_tail(&newfib->fiblink, &fibctx->fib_list); 214062306a36Sopenharmony_ci fibctx->count++; 214162306a36Sopenharmony_ci /* 214262306a36Sopenharmony_ci * Set the event to wake up the 214362306a36Sopenharmony_ci * thread that is waiting. 214462306a36Sopenharmony_ci */ 214562306a36Sopenharmony_ci complete(&fibctx->completion); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci entry = entry->next; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci /* 215062306a36Sopenharmony_ci * Set the status of this FIB 215162306a36Sopenharmony_ci */ 215262306a36Sopenharmony_ci *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); 215362306a36Sopenharmony_ci aac_fib_adapter_complete(fib, sizeof(u32)); 215462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flagv); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci} 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_cistatic void aac_process_events(struct aac_dev *dev) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci struct hw_fib *hw_fib; 216162306a36Sopenharmony_ci struct fib *fib; 216262306a36Sopenharmony_ci unsigned long flags; 216362306a36Sopenharmony_ci spinlock_t *t_lock; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci t_lock = dev->queues->queue[HostNormCmdQueue].lock; 216662306a36Sopenharmony_ci spin_lock_irqsave(t_lock, flags); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci while (!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) { 216962306a36Sopenharmony_ci struct list_head *entry; 217062306a36Sopenharmony_ci struct aac_aifcmd *aifcmd; 217162306a36Sopenharmony_ci unsigned int num; 217262306a36Sopenharmony_ci struct hw_fib **hw_fib_pool, **hw_fib_p; 217362306a36Sopenharmony_ci struct fib **fib_pool, **fib_p; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci entry = dev->queues->queue[HostNormCmdQueue].cmdq.next; 217862306a36Sopenharmony_ci list_del(entry); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci t_lock = dev->queues->queue[HostNormCmdQueue].lock; 218162306a36Sopenharmony_ci spin_unlock_irqrestore(t_lock, flags); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci fib = list_entry(entry, struct fib, fiblink); 218462306a36Sopenharmony_ci hw_fib = fib->hw_fib_va; 218562306a36Sopenharmony_ci if (dev->sa_firmware) { 218662306a36Sopenharmony_ci /* Thor AIF */ 218762306a36Sopenharmony_ci aac_handle_sa_aif(dev, fib); 218862306a36Sopenharmony_ci aac_fib_adapter_complete(fib, (u16)sizeof(u32)); 218962306a36Sopenharmony_ci goto free_fib; 219062306a36Sopenharmony_ci } 219162306a36Sopenharmony_ci /* 219262306a36Sopenharmony_ci * We will process the FIB here or pass it to a 219362306a36Sopenharmony_ci * worker thread that is TBD. We Really can't 219462306a36Sopenharmony_ci * do anything at this point since we don't have 219562306a36Sopenharmony_ci * anything defined for this thread to do. 219662306a36Sopenharmony_ci */ 219762306a36Sopenharmony_ci memset(fib, 0, sizeof(struct fib)); 219862306a36Sopenharmony_ci fib->type = FSAFS_NTC_FIB_CONTEXT; 219962306a36Sopenharmony_ci fib->size = sizeof(struct fib); 220062306a36Sopenharmony_ci fib->hw_fib_va = hw_fib; 220162306a36Sopenharmony_ci fib->data = hw_fib->data; 220262306a36Sopenharmony_ci fib->dev = dev; 220362306a36Sopenharmony_ci /* 220462306a36Sopenharmony_ci * We only handle AifRequest fibs from the adapter. 220562306a36Sopenharmony_ci */ 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci aifcmd = (struct aac_aifcmd *) hw_fib->data; 220862306a36Sopenharmony_ci if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { 220962306a36Sopenharmony_ci /* Handle Driver Notify Events */ 221062306a36Sopenharmony_ci aac_handle_aif(dev, fib); 221162306a36Sopenharmony_ci *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); 221262306a36Sopenharmony_ci aac_fib_adapter_complete(fib, (u16)sizeof(u32)); 221362306a36Sopenharmony_ci goto free_fib; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci /* 221662306a36Sopenharmony_ci * The u32 here is important and intended. We are using 221762306a36Sopenharmony_ci * 32bit wrapping time to fit the adapter field 221862306a36Sopenharmony_ci */ 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci /* Sniff events */ 222162306a36Sopenharmony_ci if (aifcmd->command == cpu_to_le32(AifCmdEventNotify) 222262306a36Sopenharmony_ci || aifcmd->command == cpu_to_le32(AifCmdJobProgress)) { 222362306a36Sopenharmony_ci aac_handle_aif(dev, fib); 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci /* 222762306a36Sopenharmony_ci * get number of fibs to process 222862306a36Sopenharmony_ci */ 222962306a36Sopenharmony_ci num = get_fib_count(dev); 223062306a36Sopenharmony_ci if (!num) 223162306a36Sopenharmony_ci goto free_fib; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci hw_fib_pool = kmalloc_array(num, sizeof(struct hw_fib *), 223462306a36Sopenharmony_ci GFP_KERNEL); 223562306a36Sopenharmony_ci if (!hw_fib_pool) 223662306a36Sopenharmony_ci goto free_fib; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci fib_pool = kmalloc_array(num, sizeof(struct fib *), GFP_KERNEL); 223962306a36Sopenharmony_ci if (!fib_pool) 224062306a36Sopenharmony_ci goto free_hw_fib_pool; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci /* 224362306a36Sopenharmony_ci * Fill up fib pointer pools with actual fibs 224462306a36Sopenharmony_ci * and hw_fibs 224562306a36Sopenharmony_ci */ 224662306a36Sopenharmony_ci num = fillup_pools(dev, hw_fib_pool, fib_pool, num); 224762306a36Sopenharmony_ci if (!num) 224862306a36Sopenharmony_ci goto free_mem; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci /* 225162306a36Sopenharmony_ci * wakeup the thread that is waiting for 225262306a36Sopenharmony_ci * the response from fw (ioctl) 225362306a36Sopenharmony_ci */ 225462306a36Sopenharmony_ci wakeup_fibctx_threads(dev, hw_fib_pool, fib_pool, 225562306a36Sopenharmony_ci fib, hw_fib, num); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_cifree_mem: 225862306a36Sopenharmony_ci /* Free up the remaining resources */ 225962306a36Sopenharmony_ci hw_fib_p = hw_fib_pool; 226062306a36Sopenharmony_ci fib_p = fib_pool; 226162306a36Sopenharmony_ci while (hw_fib_p < &hw_fib_pool[num]) { 226262306a36Sopenharmony_ci kfree(*hw_fib_p); 226362306a36Sopenharmony_ci kfree(*fib_p); 226462306a36Sopenharmony_ci ++fib_p; 226562306a36Sopenharmony_ci ++hw_fib_p; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci kfree(fib_pool); 226862306a36Sopenharmony_cifree_hw_fib_pool: 226962306a36Sopenharmony_ci kfree(hw_fib_pool); 227062306a36Sopenharmony_cifree_fib: 227162306a36Sopenharmony_ci kfree(fib); 227262306a36Sopenharmony_ci t_lock = dev->queues->queue[HostNormCmdQueue].lock; 227362306a36Sopenharmony_ci spin_lock_irqsave(t_lock, flags); 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci /* 227662306a36Sopenharmony_ci * There are no more AIF's 227762306a36Sopenharmony_ci */ 227862306a36Sopenharmony_ci t_lock = dev->queues->queue[HostNormCmdQueue].lock; 227962306a36Sopenharmony_ci spin_unlock_irqrestore(t_lock, flags); 228062306a36Sopenharmony_ci} 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_cistatic int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, 228362306a36Sopenharmony_ci u32 datasize) 228462306a36Sopenharmony_ci{ 228562306a36Sopenharmony_ci struct aac_srb *srbcmd; 228662306a36Sopenharmony_ci struct sgmap64 *sg64; 228762306a36Sopenharmony_ci dma_addr_t addr; 228862306a36Sopenharmony_ci char *dma_buf; 228962306a36Sopenharmony_ci struct fib *fibptr; 229062306a36Sopenharmony_ci int ret = -ENOMEM; 229162306a36Sopenharmony_ci u32 vbus, vid; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci fibptr = aac_fib_alloc(dev); 229462306a36Sopenharmony_ci if (!fibptr) 229562306a36Sopenharmony_ci goto out; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci dma_buf = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, 229862306a36Sopenharmony_ci GFP_KERNEL); 229962306a36Sopenharmony_ci if (!dma_buf) 230062306a36Sopenharmony_ci goto fib_free_out; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci aac_fib_init(fibptr); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.virt_device_bus); 230562306a36Sopenharmony_ci vid = (u32)le16_to_cpu(dev->supplement_adapter_info.virt_device_target); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci srbcmd = (struct aac_srb *)fib_data(fibptr); 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); 231062306a36Sopenharmony_ci srbcmd->channel = cpu_to_le32(vbus); 231162306a36Sopenharmony_ci srbcmd->id = cpu_to_le32(vid); 231262306a36Sopenharmony_ci srbcmd->lun = 0; 231362306a36Sopenharmony_ci srbcmd->flags = cpu_to_le32(SRB_DataOut); 231462306a36Sopenharmony_ci srbcmd->timeout = cpu_to_le32(10); 231562306a36Sopenharmony_ci srbcmd->retry_limit = 0; 231662306a36Sopenharmony_ci srbcmd->cdb_size = cpu_to_le32(12); 231762306a36Sopenharmony_ci srbcmd->count = cpu_to_le32(datasize); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 232062306a36Sopenharmony_ci srbcmd->cdb[0] = BMIC_OUT; 232162306a36Sopenharmony_ci srbcmd->cdb[6] = WRITE_HOST_WELLNESS; 232262306a36Sopenharmony_ci memcpy(dma_buf, (char *)wellness_str, datasize); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci sg64 = (struct sgmap64 *)&srbcmd->sg; 232562306a36Sopenharmony_ci sg64->count = cpu_to_le32(1); 232662306a36Sopenharmony_ci sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16)); 232762306a36Sopenharmony_ci sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); 232862306a36Sopenharmony_ci sg64->sg[0].count = cpu_to_le32(datasize); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci ret = aac_fib_send(ScsiPortCommand64, fibptr, sizeof(struct aac_srb), 233162306a36Sopenharmony_ci FsaNormal, 1, 1, NULL, NULL); 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, datasize, dma_buf, addr); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci /* 233662306a36Sopenharmony_ci * Do not set XferState to zero unless 233762306a36Sopenharmony_ci * receives a response from F/W 233862306a36Sopenharmony_ci */ 233962306a36Sopenharmony_ci if (ret >= 0) 234062306a36Sopenharmony_ci aac_fib_complete(fibptr); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci /* 234362306a36Sopenharmony_ci * FIB should be freed only after 234462306a36Sopenharmony_ci * getting the response from the F/W 234562306a36Sopenharmony_ci */ 234662306a36Sopenharmony_ci if (ret != -ERESTARTSYS) 234762306a36Sopenharmony_ci goto fib_free_out; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ciout: 235062306a36Sopenharmony_ci return ret; 235162306a36Sopenharmony_cifib_free_out: 235262306a36Sopenharmony_ci aac_fib_free(fibptr); 235362306a36Sopenharmony_ci goto out; 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_cistatic int aac_send_safw_hostttime(struct aac_dev *dev, struct timespec64 *now) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci struct tm cur_tm; 235962306a36Sopenharmony_ci char wellness_str[] = "<HW>TD\010\0\0\0\0\0\0\0\0\0DW\0\0ZZ"; 236062306a36Sopenharmony_ci u32 datasize = sizeof(wellness_str); 236162306a36Sopenharmony_ci time64_t local_time; 236262306a36Sopenharmony_ci int ret = -ENODEV; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci if (!dev->sa_firmware) 236562306a36Sopenharmony_ci goto out; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci local_time = (now->tv_sec - (sys_tz.tz_minuteswest * 60)); 236862306a36Sopenharmony_ci time64_to_tm(local_time, 0, &cur_tm); 236962306a36Sopenharmony_ci cur_tm.tm_mon += 1; 237062306a36Sopenharmony_ci cur_tm.tm_year += 1900; 237162306a36Sopenharmony_ci wellness_str[8] = bin2bcd(cur_tm.tm_hour); 237262306a36Sopenharmony_ci wellness_str[9] = bin2bcd(cur_tm.tm_min); 237362306a36Sopenharmony_ci wellness_str[10] = bin2bcd(cur_tm.tm_sec); 237462306a36Sopenharmony_ci wellness_str[12] = bin2bcd(cur_tm.tm_mon); 237562306a36Sopenharmony_ci wellness_str[13] = bin2bcd(cur_tm.tm_mday); 237662306a36Sopenharmony_ci wellness_str[14] = bin2bcd(cur_tm.tm_year / 100); 237762306a36Sopenharmony_ci wellness_str[15] = bin2bcd(cur_tm.tm_year % 100); 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci ret = aac_send_wellness_command(dev, wellness_str, datasize); 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ciout: 238262306a36Sopenharmony_ci return ret; 238362306a36Sopenharmony_ci} 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_cistatic int aac_send_hosttime(struct aac_dev *dev, struct timespec64 *now) 238662306a36Sopenharmony_ci{ 238762306a36Sopenharmony_ci int ret = -ENOMEM; 238862306a36Sopenharmony_ci struct fib *fibptr; 238962306a36Sopenharmony_ci __le32 *info; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci fibptr = aac_fib_alloc(dev); 239262306a36Sopenharmony_ci if (!fibptr) 239362306a36Sopenharmony_ci goto out; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci aac_fib_init(fibptr); 239662306a36Sopenharmony_ci info = (__le32 *)fib_data(fibptr); 239762306a36Sopenharmony_ci *info = cpu_to_le32(now->tv_sec); /* overflow in y2106 */ 239862306a36Sopenharmony_ci ret = aac_fib_send(SendHostTime, fibptr, sizeof(*info), FsaNormal, 239962306a36Sopenharmony_ci 1, 1, NULL, NULL); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci /* 240262306a36Sopenharmony_ci * Do not set XferState to zero unless 240362306a36Sopenharmony_ci * receives a response from F/W 240462306a36Sopenharmony_ci */ 240562306a36Sopenharmony_ci if (ret >= 0) 240662306a36Sopenharmony_ci aac_fib_complete(fibptr); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci /* 240962306a36Sopenharmony_ci * FIB should be freed only after 241062306a36Sopenharmony_ci * getting the response from the F/W 241162306a36Sopenharmony_ci */ 241262306a36Sopenharmony_ci if (ret != -ERESTARTSYS) 241362306a36Sopenharmony_ci aac_fib_free(fibptr); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ciout: 241662306a36Sopenharmony_ci return ret; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci/** 242062306a36Sopenharmony_ci * aac_command_thread - command processing thread 242162306a36Sopenharmony_ci * @data: Adapter to monitor 242262306a36Sopenharmony_ci * 242362306a36Sopenharmony_ci * Waits on the commandready event in it's queue. When the event gets set 242462306a36Sopenharmony_ci * it will pull FIBs off it's queue. It will continue to pull FIBs off 242562306a36Sopenharmony_ci * until the queue is empty. When the queue is empty it will wait for 242662306a36Sopenharmony_ci * more FIBs. 242762306a36Sopenharmony_ci */ 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ciint aac_command_thread(void *data) 243062306a36Sopenharmony_ci{ 243162306a36Sopenharmony_ci struct aac_dev *dev = data; 243262306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 243362306a36Sopenharmony_ci unsigned long next_jiffies = jiffies + HZ; 243462306a36Sopenharmony_ci unsigned long next_check_jiffies = next_jiffies; 243562306a36Sopenharmony_ci long difference = HZ; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci /* 243862306a36Sopenharmony_ci * We can only have one thread per adapter for AIF's. 243962306a36Sopenharmony_ci */ 244062306a36Sopenharmony_ci if (dev->aif_thread) 244162306a36Sopenharmony_ci return -EINVAL; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* 244462306a36Sopenharmony_ci * Let the DPC know it has a place to send the AIF's to. 244562306a36Sopenharmony_ci */ 244662306a36Sopenharmony_ci dev->aif_thread = 1; 244762306a36Sopenharmony_ci add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); 244862306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 244962306a36Sopenharmony_ci dprintk ((KERN_INFO "aac_command_thread start\n")); 245062306a36Sopenharmony_ci while (1) { 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci aac_process_events(dev); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* 245562306a36Sopenharmony_ci * Background activity 245662306a36Sopenharmony_ci */ 245762306a36Sopenharmony_ci if ((time_before(next_check_jiffies,next_jiffies)) 245862306a36Sopenharmony_ci && ((difference = next_check_jiffies - jiffies) <= 0)) { 245962306a36Sopenharmony_ci next_check_jiffies = next_jiffies; 246062306a36Sopenharmony_ci if (aac_adapter_check_health(dev) == 0) { 246162306a36Sopenharmony_ci difference = ((long)(unsigned)check_interval) 246262306a36Sopenharmony_ci * HZ; 246362306a36Sopenharmony_ci next_check_jiffies = jiffies + difference; 246462306a36Sopenharmony_ci } else if (!dev->queues) 246562306a36Sopenharmony_ci break; 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci if (!time_before(next_check_jiffies,next_jiffies) 246862306a36Sopenharmony_ci && ((difference = next_jiffies - jiffies) <= 0)) { 246962306a36Sopenharmony_ci struct timespec64 now; 247062306a36Sopenharmony_ci int ret; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci /* Don't even try to talk to adapter if its sick */ 247362306a36Sopenharmony_ci ret = aac_adapter_check_health(dev); 247462306a36Sopenharmony_ci if (ret || !dev->queues) 247562306a36Sopenharmony_ci break; 247662306a36Sopenharmony_ci next_check_jiffies = jiffies 247762306a36Sopenharmony_ci + ((long)(unsigned)check_interval) 247862306a36Sopenharmony_ci * HZ; 247962306a36Sopenharmony_ci ktime_get_real_ts64(&now); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci /* Synchronize our watches */ 248262306a36Sopenharmony_ci if (((NSEC_PER_SEC - (NSEC_PER_SEC / HZ)) > now.tv_nsec) 248362306a36Sopenharmony_ci && (now.tv_nsec > (NSEC_PER_SEC / HZ))) 248462306a36Sopenharmony_ci difference = HZ + HZ / 2 - 248562306a36Sopenharmony_ci now.tv_nsec / (NSEC_PER_SEC / HZ); 248662306a36Sopenharmony_ci else { 248762306a36Sopenharmony_ci if (now.tv_nsec > NSEC_PER_SEC / 2) 248862306a36Sopenharmony_ci ++now.tv_sec; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci if (dev->sa_firmware) 249162306a36Sopenharmony_ci ret = 249262306a36Sopenharmony_ci aac_send_safw_hostttime(dev, &now); 249362306a36Sopenharmony_ci else 249462306a36Sopenharmony_ci ret = aac_send_hosttime(dev, &now); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci difference = (long)(unsigned)update_interval*HZ; 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci next_jiffies = jiffies + difference; 249962306a36Sopenharmony_ci if (time_before(next_check_jiffies,next_jiffies)) 250062306a36Sopenharmony_ci difference = next_check_jiffies - jiffies; 250162306a36Sopenharmony_ci } 250262306a36Sopenharmony_ci if (difference <= 0) 250362306a36Sopenharmony_ci difference = 1; 250462306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (kthread_should_stop()) 250762306a36Sopenharmony_ci break; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci /* 251062306a36Sopenharmony_ci * we probably want usleep_range() here instead of the 251162306a36Sopenharmony_ci * jiffies computation 251262306a36Sopenharmony_ci */ 251362306a36Sopenharmony_ci schedule_timeout(difference); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci if (kthread_should_stop()) 251662306a36Sopenharmony_ci break; 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci if (dev->queues) 251962306a36Sopenharmony_ci remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); 252062306a36Sopenharmony_ci dev->aif_thread = 0; 252162306a36Sopenharmony_ci return 0; 252262306a36Sopenharmony_ci} 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ciint aac_acquire_irq(struct aac_dev *dev) 252562306a36Sopenharmony_ci{ 252662306a36Sopenharmony_ci int i; 252762306a36Sopenharmony_ci int j; 252862306a36Sopenharmony_ci int ret = 0; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { 253162306a36Sopenharmony_ci for (i = 0; i < dev->max_msix; i++) { 253262306a36Sopenharmony_ci dev->aac_msix[i].vector_no = i; 253362306a36Sopenharmony_ci dev->aac_msix[i].dev = dev; 253462306a36Sopenharmony_ci if (request_irq(pci_irq_vector(dev->pdev, i), 253562306a36Sopenharmony_ci dev->a_ops.adapter_intr, 253662306a36Sopenharmony_ci 0, "aacraid", &(dev->aac_msix[i]))) { 253762306a36Sopenharmony_ci printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", 253862306a36Sopenharmony_ci dev->name, dev->id, i); 253962306a36Sopenharmony_ci for (j = 0 ; j < i ; j++) 254062306a36Sopenharmony_ci free_irq(pci_irq_vector(dev->pdev, j), 254162306a36Sopenharmony_ci &(dev->aac_msix[j])); 254262306a36Sopenharmony_ci pci_disable_msix(dev->pdev); 254362306a36Sopenharmony_ci ret = -1; 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci } 254662306a36Sopenharmony_ci } else { 254762306a36Sopenharmony_ci dev->aac_msix[0].vector_no = 0; 254862306a36Sopenharmony_ci dev->aac_msix[0].dev = dev; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 255162306a36Sopenharmony_ci IRQF_SHARED, "aacraid", 255262306a36Sopenharmony_ci &(dev->aac_msix[0])) < 0) { 255362306a36Sopenharmony_ci if (dev->msi) 255462306a36Sopenharmony_ci pci_disable_msi(dev->pdev); 255562306a36Sopenharmony_ci printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 255662306a36Sopenharmony_ci dev->name, dev->id); 255762306a36Sopenharmony_ci ret = -1; 255862306a36Sopenharmony_ci } 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci return ret; 256162306a36Sopenharmony_ci} 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_civoid aac_free_irq(struct aac_dev *dev) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci int i; 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci if (aac_is_src(dev)) { 256862306a36Sopenharmony_ci if (dev->max_msix > 1) { 256962306a36Sopenharmony_ci for (i = 0; i < dev->max_msix; i++) 257062306a36Sopenharmony_ci free_irq(pci_irq_vector(dev->pdev, i), 257162306a36Sopenharmony_ci &(dev->aac_msix[i])); 257262306a36Sopenharmony_ci } else { 257362306a36Sopenharmony_ci free_irq(dev->pdev->irq, &(dev->aac_msix[0])); 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci } else { 257662306a36Sopenharmony_ci free_irq(dev->pdev->irq, dev); 257762306a36Sopenharmony_ci } 257862306a36Sopenharmony_ci if (dev->msi) 257962306a36Sopenharmony_ci pci_disable_msi(dev->pdev); 258062306a36Sopenharmony_ci else if (dev->max_msix > 1) 258162306a36Sopenharmony_ci pci_disable_msix(dev->pdev); 258262306a36Sopenharmony_ci} 2583