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