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