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