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