12908d778ab3e244900c310974e1fc1c69066e450James Bottomley/*
22908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Aic94xx SAS/SATA driver hardware interface.
32908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
42908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
52908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
62908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
72908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This file is licensed under GPLv2.
82908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
92908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This file is part of the aic94xx driver.
102908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
112908d778ab3e244900c310974e1fc1c69066e450James Bottomley * The aic94xx driver is free software; you can redistribute it and/or
122908d778ab3e244900c310974e1fc1c69066e450James Bottomley * modify it under the terms of the GNU General Public License as
132908d778ab3e244900c310974e1fc1c69066e450James Bottomley * published by the Free Software Foundation; version 2 of the
142908d778ab3e244900c310974e1fc1c69066e450James Bottomley * License.
152908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
162908d778ab3e244900c310974e1fc1c69066e450James Bottomley * The aic94xx driver is distributed in the hope that it will be useful,
172908d778ab3e244900c310974e1fc1c69066e450James Bottomley * but WITHOUT ANY WARRANTY; without even the implied warranty of
182908d778ab3e244900c310974e1fc1c69066e450James Bottomley * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
192908d778ab3e244900c310974e1fc1c69066e450James Bottomley * General Public License for more details.
202908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
212908d778ab3e244900c310974e1fc1c69066e450James Bottomley * You should have received a copy of the GNU General Public License
222908d778ab3e244900c310974e1fc1c69066e450James Bottomley * along with the aic94xx driver; if not, write to the Free Software
232908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
242908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
252908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
262908d778ab3e244900c310974e1fc1c69066e450James Bottomley
272908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include <linux/pci.h>
285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
292908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include <linux/delay.h>
302908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include <linux/module.h>
3168066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong#include <linux/firmware.h>
322908d778ab3e244900c310974e1fc1c69066e450James Bottomley
332908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include "aic94xx.h"
342908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include "aic94xx_reg.h"
352908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include "aic94xx_hwi.h"
362908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include "aic94xx_seq.h"
372908d778ab3e244900c310974e1fc1c69066e450James Bottomley#include "aic94xx_dump.h"
382908d778ab3e244900c310974e1fc1c69066e450James Bottomley
392908d778ab3e244900c310974e1fc1c69066e450James Bottomleyu32 MBAR0_SWB_SIZE;
402908d778ab3e244900c310974e1fc1c69066e450James Bottomley
412908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Initialization ---------- */
422908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4368066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wongstatic int asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
442908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
4568066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong	/* adapter came with a sas address */
4668066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong	if (asd_ha->hw_prof.sas_addr[0])
4768066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong		return 0;
4868066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong
4968066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong	return sas_request_addr(asd_ha->sas_ha.core.shost,
5068066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong				asd_ha->hw_prof.sas_addr);
512908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
522908d778ab3e244900c310974e1fc1c69066e450James Bottomley
532908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
542908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
552908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int i;
562908d778ab3e244900c310974e1fc1c69066e450James Bottomley
572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0; i < ASD_MAX_PHYS; i++) {
582908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
592908d778ab3e244900c310974e1fc1c69066e450James Bottomley			continue;
602908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* Set a phy's address only if it has none.
612908d778ab3e244900c310974e1fc1c69066e450James Bottomley		 */
622908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ASD_DPRINTK("setting phy%d addr to %llx\n", i,
632908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    SAS_ADDR(asd_ha->hw_prof.sas_addr));
642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
652908d778ab3e244900c310974e1fc1c69066e450James Bottomley		       asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
662908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
672908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
692908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- PHY initialization ---------- */
702908d778ab3e244900c310974e1fc1c69066e450James Bottomley
712908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_init_phy_identify(struct asd_phy *phy)
722908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
732908d778ab3e244900c310974e1fc1c69066e450James Bottomley	phy->identify_frame = phy->id_frm_tok->vaddr;
742908d778ab3e244900c310974e1fc1c69066e450James Bottomley
752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
762908d778ab3e244900c310974e1fc1c69066e450James Bottomley
772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	phy->identify_frame->dev_type = SAS_END_DEV;
782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
792908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (phy->sas_phy.role & PHY_ROLE_TARGET)
812908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->identify_frame->target_bits = phy->sas_phy.tproto;
822908d778ab3e244900c310974e1fc1c69066e450James Bottomley	memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	       SAS_ADDR_SIZE);
842908d778ab3e244900c310974e1fc1c69066e450James Bottomley	phy->identify_frame->phy_id = phy->sas_phy.id;
852908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
862908d778ab3e244900c310974e1fc1c69066e450James Bottomley
872908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_phy(struct asd_phy *phy)
882908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
902908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_sas_phy *sas_phy = &phy->sas_phy;
912908d778ab3e244900c310974e1fc1c69066e450James Bottomley
922908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->enabled = 1;
932908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->class = SAS;
945929faf3334f4c69f3bb02be59d7c127e0cefa1fDarrick J. Wong	sas_phy->iproto = SAS_PROTOCOL_ALL;
952908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->tproto = 0;
962908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->type = PHY_TYPE_PHYSICAL;
972908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->role = PHY_ROLE_INITIATOR;
982908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_phy->oob_mode = OOB_NOT_CONNECTED;
9988edf74610bd894b93438f389688bc8b4a2d3414James Bottomley	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
1002908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1012908d778ab3e244900c310974e1fc1c69066e450James Bottomley	phy->id_frm_tok = asd_alloc_coherent(asd_ha,
1022908d778ab3e244900c310974e1fc1c69066e450James Bottomley					     sizeof(*phy->identify_frame),
1032908d778ab3e244900c310974e1fc1c69066e450James Bottomley					     GFP_KERNEL);
1042908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!phy->id_frm_tok) {
1052908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
1062908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
1072908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else
1082908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_init_phy_identify(phy);
1092908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
1112908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1122908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
1132908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
1142908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1153f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.comstatic void asd_init_ports(struct asd_ha_struct *asd_ha)
1163f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com{
1173f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com	int i;
1183f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com
1193f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com	spin_lock_init(&asd_ha->asd_ports_lock);
1203f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com	for (i = 0; i < ASD_MAX_PHYS; i++) {
1213f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		struct asd_port *asd_port = &asd_ha->asd_ports[i];
1223f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com
1233f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE);
1243f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE);
1253f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		asd_port->phy_mask = 0;
1263f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		asd_port->num_phys = 0;
1273f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com	}
1283f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com}
1293f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com
1302908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_phys(struct asd_ha_struct *asd_ha)
1312908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
1322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u8 i;
1332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u8 phy_mask = asd_ha->hw_prof.enabled_phys;
1342908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1352908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0; i < ASD_MAX_PHYS; i++) {
1362908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct asd_phy *phy = &asd_ha->phys[i];
1372908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
1393f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com		phy->asd_port = NULL;
1402908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1412908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.enabled = 0;
1422908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.id = i;
1432908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
1442908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
1452908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.ha = &asd_ha->sas_ha;
1462908d778ab3e244900c310974e1fc1c69066e450James Bottomley		phy->sas_phy.lldd_phy = phy;
1472908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
1482908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1492908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* Now enable and initialize only the enabled phys. */
1502908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for_each_phy(phy_mask, phy_mask, i) {
1512908d778ab3e244900c310974e1fc1c69066e450James Bottomley		int err = asd_init_phy(&asd_ha->phys[i]);
1522908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (err)
1532908d778ab3e244900c310974e1fc1c69066e450James Bottomley			return err;
1542908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
1552908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
1572908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
1582908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1592908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Sliding windows ---------- */
1602908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1612908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_sw(struct asd_ha_struct *asd_ha)
1622908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
1632908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct pci_dev *pcidev = asd_ha->pcidev;
1642908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int err;
1652908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 v;
1662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1672908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* Unlock MBARs */
1682908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
1692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
1702908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't access conf. space of %s\n",
1712908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(pcidev));
1722908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Err;
1732908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
1742908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (v)
1752908d778ab3e244900c310974e1fc1c69066e450James Bottomley		err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
1762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
1772908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't write to MBAR_KEY of %s\n",
1782908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(pcidev));
1792908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Err;
1802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
1812908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1822908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* Set sliding windows A, B and C to point to proper internal
1832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 * memory regions.
1842908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 */
1852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
1862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
1872908d778ab3e244900c310974e1fc1c69066e450James Bottomley			       REG_BASE_ADDR_CSEQCIO);
1882908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
1892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
1902908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
1912908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
1922908d778ab3e244900c310974e1fc1c69066e450James Bottomley	MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
1932908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->iospace) {
1942908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* MBAR1 will point to OCM (On Chip Memory) */
1952908d778ab3e244900c310974e1fc1c69066e450James Bottomley		pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
1962908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
1972908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
1982908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_init(&asd_ha->iolock);
1992908d778ab3e244900c310974e1fc1c69066e450James BottomleyErr:
2002908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return err;
2012908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
2022908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2032908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- SCB initialization ---------- */
2042908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2052908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
2062908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_init_scbs - manually allocate the first SCB.
2072908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
2082908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
2092908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This allocates the very first SCB which would be sent to the
2102908d778ab3e244900c310974e1fc1c69066e450James Bottomley * sequencer for execution.  Its bus address is written to
2112908d778ab3e244900c310974e1fc1c69066e450James Bottomley * CSEQ_Q_NEW_POINTER, mode page 2, mode 8.  Since the bus address of
2122908d778ab3e244900c310974e1fc1c69066e450James Bottomley * the _next_ scb to be DMA-ed to the host adapter is read from the last
2132908d778ab3e244900c310974e1fc1c69066e450James Bottomley * SCB DMA-ed to the host adapter, we have to always stay one step
2142908d778ab3e244900c310974e1fc1c69066e450James Bottomley * ahead of the sequencer and keep one SCB already allocated.
2152908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
2162908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_scbs(struct asd_ha_struct *asd_ha)
2172908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
2182908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
2192908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int bitmap_bytes;
2202908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2212908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* allocate the index array and bitmap */
2222908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
2232908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
2242908d778ab3e244900c310974e1fc1c69066e450James Bottomley					     sizeof(void *), GFP_KERNEL);
2252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->seq.tc_index_array)
2262908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
2272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
2292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
2302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
2312908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->seq.tc_index_bitmap)
2322908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
2332908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_init(&seq->tc_index_lock);
2352908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2362908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->next_scb.size = sizeof(struct scb);
2372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
2382908d778ab3e244900c310974e1fc1c69066e450James Bottomley					     &seq->next_scb.dma_handle);
2392908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!seq->next_scb.vaddr) {
2402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		kfree(asd_ha->seq.tc_index_bitmap);
2412908d778ab3e244900c310974e1fc1c69066e450James Bottomley		kfree(asd_ha->seq.tc_index_array);
2422908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_ha->seq.tc_index_bitmap = NULL;
2432908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_ha->seq.tc_index_array = NULL;
2442908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
2452908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
2462908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2472908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->pending = 0;
2482908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_init(&seq->pend_q_lock);
2492908d778ab3e244900c310974e1fc1c69066e450James Bottomley	INIT_LIST_HEAD(&seq->pend_q);
2502908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2512908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
2522908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
2532908d778ab3e244900c310974e1fc1c69066e450James Bottomley
25481e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
2552908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
2562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
2572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
2582908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
2592908d778ab3e244900c310974e1fc1c69066e450James Bottomley		    asd_ha->hw_prof.max_scbs,
2602908d778ab3e244900c310974e1fc1c69066e450James Bottomley		    asd_ha->hw_prof.max_ddbs);
2612908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
2622908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2632908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Done List initialization ---------- */
2642908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2652908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_dl_tasklet_handler(unsigned long);
2662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2672908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_dl(struct asd_ha_struct *asd_ha)
2682908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
2692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.actual_dl
2702908d778ab3e244900c310974e1fc1c69066e450James Bottomley		= asd_alloc_coherent(asd_ha,
2712908d778ab3e244900c310974e1fc1c69066e450James Bottomley			     ASD_DL_SIZE * sizeof(struct done_list_struct),
2722908d778ab3e244900c310974e1fc1c69066e450James Bottomley				     GFP_KERNEL);
2732908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->seq.actual_dl)
2742908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
2752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
2762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
2772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.dl_next = 0;
2782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
2792908d778ab3e244900c310974e1fc1c69066e450James Bottomley		     (unsigned long) asd_ha);
2802908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2812908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
2822908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
2832908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2842908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- EDB and ESCB init ---------- */
2852908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2863cc27547d6ee2d50ecdd11e9127bc3cd1947e8ddAl Virostatic int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags)
2872908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
2882908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
2892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int i;
2902908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2912908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
2922908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!seq->edb_arr)
2932908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
2942908d778ab3e244900c310974e1fc1c69066e450James Bottomley
2952908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0; i < seq->num_edbs; i++) {
2962908d778ab3e244900c310974e1fc1c69066e450James Bottomley		seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
2972908d778ab3e244900c310974e1fc1c69066e450James Bottomley						     gfp_flags);
2982908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!seq->edb_arr[i])
2992908d778ab3e244900c310974e1fc1c69066e450James Bottomley			goto Err_unroll;
3002908d778ab3e244900c310974e1fc1c69066e450James Bottomley		memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
3012908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
3022908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3032908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
3042908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3052908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
3062908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3072908d778ab3e244900c310974e1fc1c69066e450James BottomleyErr_unroll:
3082908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i-- ; i >= 0; i--)
3092908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_free_coherent(asd_ha, seq->edb_arr[i]);
3102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	kfree(seq->edb_arr);
3112908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->edb_arr = NULL;
3122908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3132908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return -ENOMEM;
3142908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
3152908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3162908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
3173cc27547d6ee2d50ecdd11e9127bc3cd1947e8ddAl Viro			   gfp_t gfp_flags)
3182908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
3192908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
3202908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *escb;
3212908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int i, escbs;
3222908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3232908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
3242908d778ab3e244900c310974e1fc1c69066e450James Bottomley				gfp_flags);
3252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!seq->escb_arr)
3262908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
3272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	escbs = seq->num_escbs;
3292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
3302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!escb) {
3312908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't allocate list of escbs\n");
3322908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Err;
3332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
3342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->num_escbs -= escbs;  /* subtract what was not allocated */
3352908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
3362908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
3382908d778ab3e244900c310974e1fc1c69066e450James Bottomley							       struct asd_ascb,
3392908d778ab3e244900c310974e1fc1c69066e450James Bottomley							       list)) {
3402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		seq->escb_arr[i] = escb;
3412908d778ab3e244900c310974e1fc1c69066e450James Bottomley		escb->scb->header.opcode = EMPTY_SCB;
3422908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
3432908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3442908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
3452908d778ab3e244900c310974e1fc1c69066e450James BottomleyErr:
3462908d778ab3e244900c310974e1fc1c69066e450James Bottomley	kfree(seq->escb_arr);
3472908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->escb_arr = NULL;
3482908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return -ENOMEM;
3492908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3502908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
3512908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3522908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
3532908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
3542908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
3552908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int i, k, z = 0;
3562908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0; i < seq->num_escbs; i++) {
3582908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct asd_ascb *ascb = seq->escb_arr[i];
3592908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct empty_scb *escb = &ascb->scb->escb;
3602908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3612908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->edb_index = z;
3622908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3632908d778ab3e244900c310974e1fc1c69066e450James Bottomley		escb->num_valid = ASD_EDBS_PER_SCB;
3642908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3652908d778ab3e244900c310974e1fc1c69066e450James Bottomley		for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
3662908d778ab3e244900c310974e1fc1c69066e450James Bottomley			struct sg_el *eb = &escb->eb[k];
3672908d778ab3e244900c310974e1fc1c69066e450James Bottomley			struct asd_dma_tok *edb = seq->edb_arr[z++];
3682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3692908d778ab3e244900c310974e1fc1c69066e450James Bottomley			memset(eb, 0, sizeof(*eb));
3702908d778ab3e244900c310974e1fc1c69066e450James Bottomley			eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
3712908d778ab3e244900c310974e1fc1c69066e450James Bottomley			eb->size = cpu_to_le32(((u32) edb->size));
3722908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
3732908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
3742908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
3752908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3762908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
3772908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_init_escbs -- allocate and initialize empty scbs
3782908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
3792908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
3802908d778ab3e244900c310974e1fc1c69066e450James Bottomley * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
3812908d778ab3e244900c310974e1fc1c69066e450James Bottomley * They transport sense data, etc.
3822908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
3832908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_escbs(struct asd_ha_struct *asd_ha)
3842908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
3852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
3862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int err = 0;
3872908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3882908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* Allocate two empty data buffers (edb) per sequencer. */
3892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int edbs = 2*(1+asd_ha->hw_prof.num_phys);
3902908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3912908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
3922908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
3932908d778ab3e244900c310974e1fc1c69066e450James Bottomley
3942908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
3952908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
3962908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't allocate edbs\n");
3972908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return err;
3982908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
3992908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4002908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
4012908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
4022908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't allocate escbs\n");
4032908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return err;
4042908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
4052908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4062908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_assign_edbs2escbs(asd_ha);
4072908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* In order to insure that normal SCBs do not overfill sequencer
4082908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 * memory and leave no space for escbs (halting condition),
4092908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 * we increment pending here by the number of escbs.  However,
4102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 * escbs are never pending.
4112908d778ab3e244900c310974e1fc1c69066e450James Bottomley	 */
4122908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->pending   = seq->num_escbs;
4132908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
4142908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4152908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
4162908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
4172908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4182908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- HW initialization ---------- */
4192908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4202908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
4212908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_chip_hardrst -- hard reset the chip
4222908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
4232908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
4242908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This takes 16 cycles and is synchronous to CFCLK, which runs
4252908d778ab3e244900c310974e1fc1c69066e450James Bottomley * at 200 MHz, so this should take at most 80 nanoseconds.
4262908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
4272908d778ab3e244900c310974e1fc1c69066e450James Bottomleyint asd_chip_hardrst(struct asd_ha_struct *asd_ha)
4282908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
4292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int i;
4302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int count = 100;
4312908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 reg;
4322908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for (i = 0 ; i < 4 ; i++) {
4342908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
4352908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
4362908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	do {
4382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		udelay(1);
4392908d778ab3e244900c310974e1fc1c69066e450James Bottomley		reg = asd_read_reg_dword(asd_ha, CHIMINT);
4402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (reg & HARDRSTDET) {
4412908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_write_reg_dword(asd_ha, CHIMINT,
4422908d778ab3e244900c310974e1fc1c69066e450James Bottomley					    HARDRSTDET|PORRSTDET);
4432908d778ab3e244900c310974e1fc1c69066e450James Bottomley			return 0;
4442908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
4452908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} while (--count > 0);
4462908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4472908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return -ENODEV;
4482908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
4492908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4502908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
4512908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_init_chip -- initialize the chip
4522908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
4532908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
4542908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Hard resets the chip, disables HA interrupts, downloads the sequnecer
4552908d778ab3e244900c310974e1fc1c69066e450James Bottomley * microcode and starts the sequencers.  The caller has to explicitly
4562908d778ab3e244900c310974e1fc1c69066e450James Bottomley * enable HA interrupts with asd_enable_ints(asd_ha).
4572908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
4582908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_chip(struct asd_ha_struct *asd_ha)
4592908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
4602908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int err;
4612908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4622908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_chip_hardrst(asd_ha);
4632908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
4642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't hard reset %s\n",
4652908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    pci_name(asd_ha->pcidev));
4662908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto out;
4672908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
4682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_disable_ints(asd_ha);
4702908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4712908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_seqs(asd_ha);
4722908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
4732908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't init seqs for %s\n",
4742908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
4752908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto out;
4762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
4772908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_start_seqs(asd_ha);
4792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
4802908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("coudln't start seqs for %s\n",
4812908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
4822908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto out;
4832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
4842908d778ab3e244900c310974e1fc1c69066e450James Bottomleyout:
4852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return err;
4862908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
4872908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4882908d778ab3e244900c310974e1fc1c69066e450James Bottomley#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
4892908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4902908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int max_devs = 0;
4912908d778ab3e244900c310974e1fc1c69066e450James Bottomleymodule_param_named(max_devs, max_devs, int, S_IRUGO);
4922908d778ab3e244900c310974e1fc1c69066e450James BottomleyMODULE_PARM_DESC(max_devs, "\n"
4932908d778ab3e244900c310974e1fc1c69066e450James Bottomley	"\tMaximum number of SAS devices to support (not LUs).\n"
4942908d778ab3e244900c310974e1fc1c69066e450James Bottomley	"\tDefault: 2176, Maximum: 65663.\n");
4952908d778ab3e244900c310974e1fc1c69066e450James Bottomley
4962908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int max_cmnds = 0;
4972908d778ab3e244900c310974e1fc1c69066e450James Bottomleymodule_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
4982908d778ab3e244900c310974e1fc1c69066e450James BottomleyMODULE_PARM_DESC(max_cmnds, "\n"
4992908d778ab3e244900c310974e1fc1c69066e450James Bottomley	"\tMaximum number of commands queuable.\n"
5002908d778ab3e244900c310974e1fc1c69066e450James Bottomley	"\tDefault: 512, Maximum: 66047.\n");
5012908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5022908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
5032908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
5042908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long dma_addr = OCM_BASE_ADDR;
5052908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 d;
5062908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5072908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
5082908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
5092908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
5102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d |= 4;
5112908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
5122908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.max_ddbs += MAX_DEVS;
5132908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
5142908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5152908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_extend_devctx(struct asd_ha_struct *asd_ha)
5162908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
5172908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr_t dma_handle;
5182908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long dma_addr;
5192908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 d;
5202908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int size;
5212908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5222908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_extend_devctx_ocm(asd_ha);
5232908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5242908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.ddb_ext = NULL;
5252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
5262908d778ab3e244900c310974e1fc1c69066e450James Bottomley		max_devs = asd_ha->hw_prof.max_ddbs;
5272908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return 0;
5282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
5292908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
5312908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
5332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->hw_prof.ddb_ext) {
5342908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't allocate memory for %d devices\n",
5352908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   max_devs);
5362908d778ab3e244900c310974e1fc1c69066e450James Bottomley		max_devs = asd_ha->hw_prof.max_ddbs;
5372908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
5382908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
5392908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
5402908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
5412908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
5422908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_handle = (dma_addr_t) dma_addr;
5432908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
5442908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
5452908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d &= ~4;
5462908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
5472908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5482908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.max_ddbs = max_devs;
5492908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5502908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
5512908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
5522908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5532908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
5542908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
5552908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr_t dma_handle;
5562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long dma_addr;
5572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 d;
5582908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int size;
5592908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5602908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.scb_ext = NULL;
5612908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
5622908d778ab3e244900c310974e1fc1c69066e450James Bottomley		max_cmnds = asd_ha->hw_prof.max_scbs;
5632908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return 0;
5642908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
5652908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5662908d778ab3e244900c310974e1fc1c69066e450James Bottomley	size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
5672908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5682908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
5692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->hw_prof.scb_ext) {
5702908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't allocate memory for %d commands\n",
5712908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   max_cmnds);
5722908d778ab3e244900c310974e1fc1c69066e450James Bottomley		max_cmnds = asd_ha->hw_prof.max_scbs;
5732908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
5742908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
5752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
5762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
5772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
5782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_handle = (dma_addr_t) dma_addr;
5792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
5802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
5812908d778ab3e244900c310974e1fc1c69066e450James Bottomley	d &= ~1;
5822908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
5832908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5842908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.max_scbs = max_cmnds;
5852908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
5872908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
5882908d778ab3e244900c310974e1fc1c69066e450James Bottomley
5892908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
5902908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_init_ctxmem -- initialize context memory
5912908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_ha: pointer to host adapter structure
5922908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
5932908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This function sets the maximum number of SCBs and
5942908d778ab3e244900c310974e1fc1c69066e450James Bottomley * DDBs which can be used by the sequencer.  This is normally
5952908d778ab3e244900c310974e1fc1c69066e450James Bottomley * 512 and 128 respectively.  If support for more SCBs or more DDBs
5962908d778ab3e244900c310974e1fc1c69066e450James Bottomley * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
5972908d778ab3e244900c310974e1fc1c69066e450James Bottomley * initialized here to extend context memory to point to host memory,
5982908d778ab3e244900c310974e1fc1c69066e450James Bottomley * thus allowing unlimited support for SCBs and DDBs -- only limited
5992908d778ab3e244900c310974e1fc1c69066e450James Bottomley * by host memory.
6002908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
6012908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
6022908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
6032908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int bitmap_bytes;
6042908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6052908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_get_max_scb_ddb(asd_ha);
6062908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_extend_devctx(asd_ha);
6072908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_extend_cmdctx(asd_ha);
6082908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6092908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* The kernel wants bitmaps to be unsigned long sized. */
6102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
6112908d778ab3e244900c310974e1fc1c69066e450James Bottomley	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
6122908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
6132908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!asd_ha->hw_prof.ddb_bitmap)
6142908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
6152908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_init(&asd_ha->hw_prof.ddb_lock);
6162908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6172908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
6182908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
6192908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6202908d778ab3e244900c310974e1fc1c69066e450James Bottomleyint asd_init_hw(struct asd_ha_struct *asd_ha)
6212908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
6222908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int err;
6232908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 v;
6242908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_sw(asd_ha);
6262908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err)
6272908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return err;
6282908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);
6302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6312908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",
6322908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
6332908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return err;
6342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6352908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
6362908d778ab3e244900c310974e1fc1c69066e450James Bottomley					v | SC_TMR_DIS);
6372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't disable split completion timer of %s\n",
6392908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
6402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return err;
6412908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6422908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6432908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_read_ocm(asd_ha);
6442908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6452908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't read ocm(%d)\n", err);
6462908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* While suspicios, it is not an error that we
6472908d778ab3e244900c310974e1fc1c69066e450James Bottomley		 * couldn't read the OCM. */
6482908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6492908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6502908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_read_flash(asd_ha);
6512908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6522908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't read flash(%d)\n", err);
6532908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* While suspicios, it is not an error that we
6542908d778ab3e244900c310974e1fc1c69066e450James Bottomley		 * couldn't read FLASH memory.
6552908d778ab3e244900c310974e1fc1c69066e450James Bottomley		 */
6562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6572908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6582908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_init_ctxmem(asd_ha);
6592908d778ab3e244900c310974e1fc1c69066e450James Bottomley
66068066c3ed14b529331bc2ff12470e9ca1cae5c3fDarrick J. Wong	if (asd_get_user_sas_addr(asd_ha)) {
6612908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("No SAS Address provided for %s\n",
6622908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
6632908d778ab3e244900c310974e1fc1c69066e450James Bottomley		err = -ENODEV;
6642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
6652908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6672908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_propagate_sas_addr(asd_ha);
6682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_phys(asd_ha);
6702908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6712908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't initialize phys for %s\n",
6722908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    pci_name(asd_ha->pcidev));
6732908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
6742908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6752908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6763f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com	asd_init_ports(asd_ha);
6773f048109d9c4f8bb028ccb0d256ab65eb44f5988malahal@us.ibm.com
6782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_scbs(asd_ha);
6792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6802908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't initialize scbs for %s\n",
6812908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    pci_name(asd_ha->pcidev));
6822908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
6832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6842908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_dl(asd_ha);
6862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6872908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't initialize the done list:%d\n",
6882908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    err);
6892908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
6902908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6912908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6922908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_escbs(asd_ha);
6932908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
6942908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't initialize escbs\n");
6952908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
6962908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
6972908d778ab3e244900c310974e1fc1c69066e450James Bottomley
6982908d778ab3e244900c310974e1fc1c69066e450James Bottomley	err = asd_init_chip(asd_ha);
6992908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (err) {
7002908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("couldn't init the chip\n");
7012908d778ab3e244900c310974e1fc1c69066e450James Bottomley		goto Out;
7022908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
7032908d778ab3e244900c310974e1fc1c69066e450James BottomleyOut:
7042908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return err;
7052908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
7062908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7072908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Chip reset ---------- */
7082908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7092908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
7102908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_chip_reset -- reset the host adapter, etc
7112908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure of interest
7122908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
7132908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Called from the ISR.  Hard reset the chip.  Let everything
7142908d778ab3e244900c310974e1fc1c69066e450James Bottomley * timeout.  This should be no different than hot-unplugging the
7152908d778ab3e244900c310974e1fc1c69066e450James Bottomley * host adapter.  Once everything times out we'll init the chip with
7162908d778ab3e244900c310974e1fc1c69066e450James Bottomley * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
7172908d778ab3e244900c310974e1fc1c69066e450James Bottomley * XXX finish.
7182908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
7192908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_chip_reset(struct asd_ha_struct *asd_ha)
7202908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
7212908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
7222908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7232908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
7242908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_chip_hardrst(asd_ha);
7252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	sas_ha->notify_ha_event(sas_ha, HAE_RESET);
7262908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
7272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7282908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Done List Routines ---------- */
7292908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7302908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic void asd_dl_tasklet_handler(unsigned long data)
7312908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
7322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
7332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
7342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long flags;
7352908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7362908d778ab3e244900c310974e1fc1c69066e450James Bottomley	while (1) {
7372908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct done_list_struct *dl = &seq->dl[seq->dl_next];
7382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct asd_ascb *ascb;
7392908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
7412908d778ab3e244900c310974e1fc1c69066e450James Bottomley			break;
7422908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7432908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* find the aSCB */
7442908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_lock_irqsave(&seq->tc_index_lock, flags);
7452908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
7462908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_unlock_irqrestore(&seq->tc_index_lock, flags);
7472908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (unlikely(!ascb)) {
7482908d778ab3e244900c310974e1fc1c69066e450James Bottomley			ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
7492908d778ab3e244900c310974e1fc1c69066e450James Bottomley			goto next_1;
7502908d778ab3e244900c310974e1fc1c69066e450James Bottomley		} else if (ascb->scb->header.opcode == EMPTY_SCB) {
7512908d778ab3e244900c310974e1fc1c69066e450James Bottomley			goto out;
7522908d778ab3e244900c310974e1fc1c69066e450James Bottomley		} else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
7532908d778ab3e244900c310974e1fc1c69066e450James Bottomley			goto next_1;
7542908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
7552908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_lock_irqsave(&seq->pend_q_lock, flags);
7562908d778ab3e244900c310974e1fc1c69066e450James Bottomley		list_del_init(&ascb->list);
7572908d778ab3e244900c310974e1fc1c69066e450James Bottomley		seq->pending--;
7582908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_unlock_irqrestore(&seq->pend_q_lock, flags);
7592908d778ab3e244900c310974e1fc1c69066e450James Bottomley	out:
7602908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->tasklet_complete(ascb, dl);
7612908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7622908d778ab3e244900c310974e1fc1c69066e450James Bottomley	next_1:
7632908d778ab3e244900c310974e1fc1c69066e450James Bottomley		seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
7642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!seq->dl_next)
7652908d778ab3e244900c310974e1fc1c69066e450James Bottomley			seq->dl_toggle ^= DL_TOGGLE_MASK;
7662908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
7672908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
7682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7692908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- Interrupt Service Routines ---------- */
7702908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7712908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
7722908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_process_donelist_isr -- schedule processing of done list entries
7732908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
7742908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
77581e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
7762908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
7772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	tasklet_schedule(&asd_ha->seq.dl_tasklet);
7782908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
7792908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7802908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
7812908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_com_sas_isr -- process device communication interrupt (COMINT)
7822908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
7832908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
78481e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
7852908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
7862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
7872908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7882908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* clear COMSTAT int */
7892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
7902908d778ab3e244900c310974e1fc1c69066e450James Bottomley
7912908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (comstat & CSBUFPERR) {
7922908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("%s: command/status buffer dma parity error\n",
7932908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
7942908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else if (comstat & CSERR) {
7952908d778ab3e244900c310974e1fc1c69066e450James Bottomley		int i;
7962908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
7972908d778ab3e244900c310974e1fc1c69066e450James Bottomley		dmaerr &= 0xFF;
7982908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
7992908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
8002908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev),
8012908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   dmaerr,
8022908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   asd_read_reg_dword(asd_ha, CSDMAADR),
8032908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   asd_read_reg_dword(asd_ha, CSDMAADR+4));
8042908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("CSBUFFER:\n");
8052908d778ab3e244900c310974e1fc1c69066e450James Bottomley		for (i = 0; i < 8; i++) {
8062908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_printk("%08x %08x %08x %08x\n",
8072908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   asd_read_reg_dword(asd_ha, CSBUFFER),
8082908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   asd_read_reg_dword(asd_ha, CSBUFFER+4),
8092908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   asd_read_reg_dword(asd_ha, CSBUFFER+8),
8102908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   asd_read_reg_dword(asd_ha, CSBUFFER+12));
8112908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
8122908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_dump_seq_state(asd_ha, 0);
8132908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else if (comstat & OVLYERR) {
8142908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
8152908d778ab3e244900c310974e1fc1c69066e450James Bottomley		dmaerr = (dmaerr >> 8) & 0xFF;
8162908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("%s: overlay dma error:0x%x\n",
8172908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev),
8182908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   dmaerr);
8192908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
8202908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_chip_reset(asd_ha);
8212908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
8222908d778ab3e244900c310974e1fc1c69066e450James Bottomley
82381e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
8242908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
8252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	static const char *halt_code[256] = {
8262908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT0",
8272908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT1",
8282908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT2",
8292908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT3",
8302908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT4",
8312908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT5",
8322908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT6",
8332908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT7",
8342908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT8",
8352908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT9",
8362908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"UNEXPECTED_INTERRUPT10",
8372908d778ab3e244900c310974e1fc1c69066e450James Bottomley		[11 ... 19] = "unknown[11,19]",
8382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"NO_FREE_SCB_AVAILABLE",
8392908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"INVALID_SCB_OPCODE",
8402908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"INVALID_MBX_OPCODE",
8412908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"INVALID_ATA_STATE",
8422908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"ATA_QUEUE_FULL",
8432908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"ATA_TAG_TABLE_FAULT",
8442908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"ATA_TAG_MASK_FAULT",
8452908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"BAD_LINK_QUEUE_STATE",
8462908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"DMA2CHIM_QUEUE_ERROR",
8472908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"EMPTY_SCB_LIST_FULL",
8482908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"unknown[30]",
8492908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"IN_USE_SCB_ON_FREE_LIST",
8502908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"BAD_OPEN_WAIT_STATE",
8512908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"INVALID_STP_AFFILIATION",
8522908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"unknown[34]",
8532908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"EXEC_QUEUE_ERROR",
8542908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"TOO_MANY_EMPTIES_NEEDED",
8552908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"EMPTY_REQ_QUEUE_ERROR",
8562908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"Q_MONIRTT_MGMT_ERROR",
8572908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"TARGET_MODE_FLOW_ERROR",
8582908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"DEVICE_QUEUE_NOT_FOUND",
8592908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"START_IRTT_TIMER_ERROR",
8602908d778ab3e244900c310974e1fc1c69066e450James Bottomley		"ABORT_TASK_ILLEGAL_REQ",
8612908d778ab3e244900c310974e1fc1c69066e450James Bottomley		[43 ... 255] = "unknown[43,255]"
8622908d778ab3e244900c310974e1fc1c69066e450James Bottomley	};
8632908d778ab3e244900c310974e1fc1c69066e450James Bottomley
8642908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (dchstatus & CSEQINT) {
8652908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
8662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
8672908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
8682908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_printk("%s: CSEQ arp2int:0x%x\n",
8692908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   pci_name(asd_ha->pcidev),
8702908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   arp2int);
8712908d778ab3e244900c310974e1fc1c69066e450James Bottomley		} else if (arp2int & ARP2HALTC)
8722908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_printk("%s: CSEQ halted: %s\n",
8732908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   pci_name(asd_ha->pcidev),
8742908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   halt_code[(arp2int>>16)&0xFF]);
8752908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else
8762908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_printk("%s: CARP2INT:0x%x\n",
8772908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   pci_name(asd_ha->pcidev),
8782908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   arp2int);
8792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
8802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (dchstatus & LSEQINT_MASK) {
8812908d778ab3e244900c310974e1fc1c69066e450James Bottomley		int lseq;
8822908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u8  lseq_mask = dchstatus & LSEQINT_MASK;
8832908d778ab3e244900c310974e1fc1c69066e450James Bottomley
8842908d778ab3e244900c310974e1fc1c69066e450James Bottomley		for_each_sequencer(lseq_mask, lseq_mask, lseq) {
8852908d778ab3e244900c310974e1fc1c69066e450James Bottomley			u32 arp2int = asd_read_reg_dword(asd_ha,
8862908d778ab3e244900c310974e1fc1c69066e450James Bottomley							 LmARP2INT(lseq));
8872908d778ab3e244900c310974e1fc1c69066e450James Bottomley			if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
8882908d778ab3e244900c310974e1fc1c69066e450James Bottomley				       | ARP2CIOPERR)) {
8892908d778ab3e244900c310974e1fc1c69066e450James Bottomley				asd_printk("%s: LSEQ%d arp2int:0x%x\n",
8902908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   pci_name(asd_ha->pcidev),
8912908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   lseq, arp2int);
8922908d778ab3e244900c310974e1fc1c69066e450James Bottomley				/* XXX we should only do lseq reset */
8932908d778ab3e244900c310974e1fc1c69066e450James Bottomley			} else if (arp2int & ARP2HALTC)
8942908d778ab3e244900c310974e1fc1c69066e450James Bottomley				asd_printk("%s: LSEQ%d halted: %s\n",
8952908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   pci_name(asd_ha->pcidev),
8962908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   lseq,halt_code[(arp2int>>16)&0xFF]);
8972908d778ab3e244900c310974e1fc1c69066e450James Bottomley			else
8982908d778ab3e244900c310974e1fc1c69066e450James Bottomley				asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
8992908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   pci_name(asd_ha->pcidev), lseq,
9002908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   arp2int);
9012908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
9022908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
9032908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_chip_reset(asd_ha);
9042908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
9052908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9062908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
9072908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
9082908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
9092908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
91081e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
9112908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
9122908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
9132908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9142908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (dchstatus & CFIFTOERR) {
9152908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
9162908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_chip_reset(asd_ha);
9172908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else
9182908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_arp2_err(asd_ha, dchstatus);
9192908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
9202908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9212908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
9222908d778ab3e244900c310974e1fc1c69066e450James Bottomley * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
9232908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
9242908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
92581e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
9262908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
9272908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
9282908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!(stat0r & ASIERR)) {
9302908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("hmm, EXSI interrupted but no error?\n");
9312908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return;
9322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
9332908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (stat0r & ASIFMTERR) {
9352908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("ASI SEEPROM format error for %s\n",
9362908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
9372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else if (stat0r & ASISEECHKERR) {
9382908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
9392908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
9402908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   stat1r & CHECKSUM_MASK,
9412908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
9422908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else {
9432908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
9442908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9452908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!(statr & CPI2ASIMSTERR_MASK)) {
9462908d778ab3e244900c310974e1fc1c69066e450James Bottomley			ASD_DPRINTK("hmm, ASIERR?\n");
9472908d778ab3e244900c310974e1fc1c69066e450James Bottomley			return;
9482908d778ab3e244900c310974e1fc1c69066e450James Bottomley		} else {
9492908d778ab3e244900c310974e1fc1c69066e450James Bottomley			u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
9502908d778ab3e244900c310974e1fc1c69066e450James Bottomley			u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
9512908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9522908d778ab3e244900c310974e1fc1c69066e450James Bottomley			asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
9532908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
9542908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   "master id: 0x%x, master err: 0x%x\n",
9552908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   pci_name(asd_ha->pcidev),
9562908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   addr, data,
9572908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   (statr & CPI2ASIBYTECNT_MASK) >> 16,
9582908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   (statr & CPI2ASIBYTEEN_MASK) >> 12,
9592908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   (statr & CPI2ASITARGERR_MASK) >> 8,
9602908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   (statr & CPI2ASITARGMID_MASK) >> 4,
9612908d778ab3e244900c310974e1fc1c69066e450James Bottomley				   (statr & CPI2ASIMSTERR_MASK));
9622908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
9632908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
9642908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_chip_reset(asd_ha);
9652908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
9662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9672908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
9682908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_hst_pcix_isr -- process host interface interrupts
9692908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
9702908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
9712908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Asserted on PCIX errors: target abort, etc.
9722908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
97381e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
9742908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
9752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u16 status;
9762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 pcix_status;
9772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 ecc_status;
9782908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
9802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
9812908d778ab3e244900c310974e1fc1c69066e450James Bottomley	pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
9822908d778ab3e244900c310974e1fc1c69066e450James Bottomley
9832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (status & PCI_STATUS_DETECTED_PARITY)
9842908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
9852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else if (status & PCI_STATUS_REC_MASTER_ABORT)
9862908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
9872908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else if (status & PCI_STATUS_REC_TARGET_ABORT)
9882908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
9892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else if (status & PCI_STATUS_PARITY)
9902908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
9912908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else if (pcix_status & RCV_SCE) {
9922908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("received split completion error for %s\n",
9932908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
9942908d778ab3e244900c310974e1fc1c69066e450James Bottomley		pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
9952908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* XXX: Abort task? */
9962908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return;
9972908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else if (pcix_status & UNEXP_SC) {
9982908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("unexpected split completion for %s\n",
9992908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
10002908d778ab3e244900c310974e1fc1c69066e450James Bottomley		pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
10012908d778ab3e244900c310974e1fc1c69066e450James Bottomley		/* ignore */
10022908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return;
10032908d778ab3e244900c310974e1fc1c69066e450James Bottomley	} else if (pcix_status & SC_DISCARD)
10042908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("split completion discarded for %s\n",
10052908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
10062908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else if (ecc_status & UNCOR_ECCERR)
10072908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("uncorrectable ECC error for %s\n",
10082908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   pci_name(asd_ha->pcidev));
10092908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_chip_reset(asd_ha);
10102908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
10112908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10122908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
10132908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_hw_isr -- host adapter interrupt service routine
10142908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @irq: ignored
10152908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @dev_id: pointer to host adapter structure
10162908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
10172908d778ab3e244900c310974e1fc1c69066e450James Bottomley * The ISR processes done list entries and level 3 error handling.
10182908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
10197d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsirqreturn_t asd_hw_isr(int irq, void *dev_id)
10202908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
10212908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ha_struct *asd_ha = dev_id;
10222908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
10232908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10242908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!chimint)
10252908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return IRQ_NONE;
10262908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10272908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, CHIMINT, chimint);
10282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	(void) asd_read_reg_dword(asd_ha, CHIMINT);
10292908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (chimint & DLAVAIL)
10312908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_process_donelist_isr(asd_ha);
10322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (chimint & COMINT)
10332908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_com_sas_isr(asd_ha);
10342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (chimint & DEVINT)
10352908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_dch_sas_isr(asd_ha);
10362908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (chimint & INITERR)
10372908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_rbi_exsi_isr(asd_ha);
10382908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (chimint & HOSTERR)
10392908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_hst_pcix_isr(asd_ha);
10402908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10412908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return IRQ_HANDLED;
10422908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
10432908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10442908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- SCB handling ---------- */
10452908d778ab3e244900c310974e1fc1c69066e450James Bottomley
104681e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
104781e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunk				       gfp_t gfp_flags)
10482908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
1049e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameter	extern struct kmem_cache *asd_ascb_cache;
10502908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
10512908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *ascb;
10522908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long flags;
10532908d778ab3e244900c310974e1fc1c69066e450James Bottomley
1054c376222960ae91d5ffb9197ee36771aaed1d9f90Robert P. J. Day	ascb = kmem_cache_zalloc(asd_ascb_cache, gfp_flags);
10552908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (ascb) {
10572908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->dma_scb.size = sizeof(struct scb);
10582908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
10592908d778ab3e244900c310974e1fc1c69066e450James Bottomley						     gfp_flags,
10602908d778ab3e244900c310974e1fc1c69066e450James Bottomley						    &ascb->dma_scb.dma_handle);
10612908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!ascb->dma_scb.vaddr) {
10622908d778ab3e244900c310974e1fc1c69066e450James Bottomley			kmem_cache_free(asd_ascb_cache, ascb);
10632908d778ab3e244900c310974e1fc1c69066e450James Bottomley			return NULL;
10642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
10652908d778ab3e244900c310974e1fc1c69066e450James Bottomley		memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
10662908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_init_ascb(asd_ha, ascb);
10672908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10682908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_lock_irqsave(&seq->tc_index_lock, flags);
10692908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->tc_index = asd_tc_index_get(seq, ascb);
10702908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_unlock_irqrestore(&seq->tc_index_lock, flags);
10712908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (ascb->tc_index == -1)
10722908d778ab3e244900c310974e1fc1c69066e450James Bottomley			goto undo;
10732908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10742908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
10752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
10762908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return ascb;
10782908d778ab3e244900c310974e1fc1c69066e450James Bottomleyundo:
10792908d778ab3e244900c310974e1fc1c69066e450James Bottomley	dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
10802908d778ab3e244900c310974e1fc1c69066e450James Bottomley		      ascb->dma_scb.dma_handle);
10812908d778ab3e244900c310974e1fc1c69066e450James Bottomley	kmem_cache_free(asd_ascb_cache, ascb);
10822908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("no index for ascb\n");
10832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return NULL;
10842908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
10852908d778ab3e244900c310974e1fc1c69066e450James Bottomley
10862908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
10872908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_ascb_alloc_list -- allocate a list of aSCBs
10882908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
10892908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @num: pointer to integer number of aSCBs
10902908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @gfp_flags: GFP_ flags.
10912908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
10922908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This is the only function which is used to allocate aSCBs.
10932908d778ab3e244900c310974e1fc1c69066e450James Bottomley * It can allocate one or many. If more than one, then they form
10942908d778ab3e244900c310974e1fc1c69066e450James Bottomley * a linked list in two ways: by their list field of the ascb struct
10952908d778ab3e244900c310974e1fc1c69066e450James Bottomley * and by the next_scb field of the scb_header.
10962908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
10972908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Returns NULL if no memory was available, else pointer to a list
10982908d778ab3e244900c310974e1fc1c69066e450James Bottomley * of ascbs.  When this function returns, @num would be the number
10992908d778ab3e244900c310974e1fc1c69066e450James Bottomley * of SCBs which were not able to be allocated, 0 if all requested
11002908d778ab3e244900c310974e1fc1c69066e450James Bottomley * were able to be allocated.
11012908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
11022908d778ab3e244900c310974e1fc1c69066e450James Bottomleystruct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
11032908d778ab3e244900c310974e1fc1c69066e450James Bottomley				     *asd_ha, int *num,
11043cc27547d6ee2d50ecdd11e9127bc3cd1947e8ddAl Viro				     gfp_t gfp_flags)
11052908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
11062908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *first = NULL;
11072908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11082908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for ( ; *num > 0; --*num) {
11092908d778ab3e244900c310974e1fc1c69066e450James Bottomley		struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
11102908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11112908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!ascb)
11122908d778ab3e244900c310974e1fc1c69066e450James Bottomley			break;
11132908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else if (!first)
11142908d778ab3e244900c310974e1fc1c69066e450James Bottomley			first = ascb;
11152908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else {
11162908d778ab3e244900c310974e1fc1c69066e450James Bottomley			struct asd_ascb *last = list_entry(first->list.prev,
11172908d778ab3e244900c310974e1fc1c69066e450James Bottomley							   struct asd_ascb,
11182908d778ab3e244900c310974e1fc1c69066e450James Bottomley							   list);
11192908d778ab3e244900c310974e1fc1c69066e450James Bottomley			list_add_tail(&ascb->list, &first->list);
11202908d778ab3e244900c310974e1fc1c69066e450James Bottomley			last->scb->header.next_scb =
11212908d778ab3e244900c310974e1fc1c69066e450James Bottomley				cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
11222908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
11232908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
11242908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11252908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return first;
11262908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
11272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11282908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
11292908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_swap_head_scb -- swap the head scb
11302908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
11312908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @ascb: pointer to the head of an ascb list
11322908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
11332908d778ab3e244900c310974e1fc1c69066e450James Bottomley * The sequencer knows the DMA address of the next SCB to be DMAed to
11342908d778ab3e244900c310974e1fc1c69066e450James Bottomley * the host adapter, from initialization or from the last list DMAed.
11352908d778ab3e244900c310974e1fc1c69066e450James Bottomley * seq->next_scb keeps the address of this SCB.  The sequencer will
11362908d778ab3e244900c310974e1fc1c69066e450James Bottomley * DMA to the host adapter this list of SCBs.  But the head (first
11372908d778ab3e244900c310974e1fc1c69066e450James Bottomley * element) of this list is not known to the sequencer.  Here we swap
11382908d778ab3e244900c310974e1fc1c69066e450James Bottomley * the head of the list with the known SCB (memcpy()).
11392908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Only one memcpy() is required per list so it is in our interest
11402908d778ab3e244900c310974e1fc1c69066e450James Bottomley * to keep the list of SCB as long as possible so that the ratio
11412908d778ab3e244900c310974e1fc1c69066e450James Bottomley * of number of memcpy calls to the number of SCB DMA-ed is as small
11422908d778ab3e244900c310974e1fc1c69066e450James Bottomley * as possible.
11432908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
11442908d778ab3e244900c310974e1fc1c69066e450James Bottomley * LOCKING: called with the pending list lock held.
11452908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
114681e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
114781e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunk			      struct asd_ascb *ascb)
11482908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
11492908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_seq_data *seq = &asd_ha->seq;
11502908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *last = list_entry(ascb->list.prev,
11512908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   struct asd_ascb,
11522908d778ab3e244900c310974e1fc1c69066e450James Bottomley					   list);
11532908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_dma_tok t = ascb->dma_scb;
11542908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11552908d778ab3e244900c310974e1fc1c69066e450James Bottomley	memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
11562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ascb->dma_scb = seq->next_scb;
11572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ascb->scb = ascb->dma_scb.vaddr;
11582908d778ab3e244900c310974e1fc1c69066e450James Bottomley	seq->next_scb = t;
11592908d778ab3e244900c310974e1fc1c69066e450James Bottomley	last->scb->header.next_scb =
11602908d778ab3e244900c310974e1fc1c69066e450James Bottomley		cpu_to_le64(((u64)seq->next_scb.dma_handle));
11612908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
11622908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11632908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
11642908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_start_timers -- (add and) start timers of SCBs
11652908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @list: pointer to struct list_head of the scbs
11662908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @to: timeout in jiffies
11672908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
11682908d778ab3e244900c310974e1fc1c69066e450James Bottomley * If an SCB in the @list has no timer function, assign the default
11692908d778ab3e244900c310974e1fc1c69066e450James Bottomley * one,  then start the timer of the SCB.  This function is
11702908d778ab3e244900c310974e1fc1c69066e450James Bottomley * intended to be called from asd_post_ascb_list(), just prior to
11712908d778ab3e244900c310974e1fc1c69066e450James Bottomley * posting the SCBs to the sequencer.
11722908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
117381e56ded878aeb8730f18c1d0a70d5face788be3Adrian Bunkstatic void asd_start_scb_timers(struct list_head *list)
11742908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
11752908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *ascb;
11762908d778ab3e244900c310974e1fc1c69066e450James Bottomley	list_for_each_entry(ascb, list, list) {
11772908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (!ascb->uldd_timer) {
11782908d778ab3e244900c310974e1fc1c69066e450James Bottomley			ascb->timer.data = (unsigned long) ascb;
11792908d778ab3e244900c310974e1fc1c69066e450James Bottomley			ascb->timer.function = asd_ascb_timedout;
11802908d778ab3e244900c310974e1fc1c69066e450James Bottomley			ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
11812908d778ab3e244900c310974e1fc1c69066e450James Bottomley			add_timer(&ascb->timer);
11822908d778ab3e244900c310974e1fc1c69066e450James Bottomley		}
11832908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
11842908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
11852908d778ab3e244900c310974e1fc1c69066e450James Bottomley
11862908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
11872908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
11882908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to a host adapter structure
11892908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @ascb: pointer to the first aSCB in the list
11902908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @num: number of aSCBs in the list (to be posted)
11912908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
11922908d778ab3e244900c310974e1fc1c69066e450James Bottomley * See queueing comment in asd_post_escb_list().
11932908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
11942908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Additional note on queuing: In order to minimize the ratio of memcpy()
11952908d778ab3e244900c310974e1fc1c69066e450James Bottomley * to the number of ascbs sent, we try to batch-send as many ascbs as possible
11962908d778ab3e244900c310974e1fc1c69066e450James Bottomley * in one go.
11972908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Two cases are possible:
11982908d778ab3e244900c310974e1fc1c69066e450James Bottomley *    A) can_queue >= num,
11992908d778ab3e244900c310974e1fc1c69066e450James Bottomley *    B) can_queue < num.
12002908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Case A: we can send the whole batch at once.  Increment "pending"
12012908d778ab3e244900c310974e1fc1c69066e450James Bottomley * in the beginning of this function, when it is checked, in order to
12022908d778ab3e244900c310974e1fc1c69066e450James Bottomley * eliminate races when this function is called by multiple processes.
12032908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Case B: should never happen if the managing layer considers
12042908d778ab3e244900c310974e1fc1c69066e450James Bottomley * lldd_queue_size.
12052908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
12062908d778ab3e244900c310974e1fc1c69066e450James Bottomleyint asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
12072908d778ab3e244900c310974e1fc1c69066e450James Bottomley		       int num)
12082908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
12092908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long flags;
12102908d778ab3e244900c310974e1fc1c69066e450James Bottomley	LIST_HEAD(list);
12112908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int can_queue;
12122908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12132908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
12142908d778ab3e244900c310974e1fc1c69066e450James Bottomley	can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
12152908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (can_queue >= num)
12162908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_ha->seq.pending += num;
12172908d778ab3e244900c310974e1fc1c69066e450James Bottomley	else
12182908d778ab3e244900c310974e1fc1c69066e450James Bottomley		can_queue = 0;
12192908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12202908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!can_queue) {
12212908d778ab3e244900c310974e1fc1c69066e450James Bottomley		spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
12222908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
12232908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -SAS_QUEUE_FULL;
12242908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
12252908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12262908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_swap_head_scb(asd_ha, ascb);
12272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	__list_add(&list, ascb->list.prev, &ascb->list);
12292908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12302908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_start_scb_timers(&list);
12312908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.scbpro += num;
12332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	list_splice_init(&list, asd_ha->seq.pend_q.prev);
12342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
12352908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
12362908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12372908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
12382908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
12392908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12402908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
12412908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_post_escb_list -- post a list of 1 or more empty scb
12422908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to a host adapter structure
12432908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @ascb: pointer to the first empty SCB in the list
12442908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @num: number of aSCBs in the list (to be posted)
12452908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
12462908d778ab3e244900c310974e1fc1c69066e450James Bottomley * This is essentially the same as asd_post_ascb_list, but we do not
12472908d778ab3e244900c310974e1fc1c69066e450James Bottomley * increment pending, add those to the pending list or get indexes.
12482908d778ab3e244900c310974e1fc1c69066e450James Bottomley * See asd_init_escbs() and asd_init_post_escbs().
12492908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
12502908d778ab3e244900c310974e1fc1c69066e450James Bottomley * Since sending a list of ascbs is a superset of sending a single
12512908d778ab3e244900c310974e1fc1c69066e450James Bottomley * ascb, this function exists to generalize this.  More specifically,
12522908d778ab3e244900c310974e1fc1c69066e450James Bottomley * when sending a list of those, we want to do only a _single_
12532908d778ab3e244900c310974e1fc1c69066e450James Bottomley * memcpy() at swap head, as opposed to for each ascb sent (in the
12542908d778ab3e244900c310974e1fc1c69066e450James Bottomley * case of sending them one by one).  That is, we want to minimize the
12552908d778ab3e244900c310974e1fc1c69066e450James Bottomley * ratio of memcpy() operations to the number of ascbs sent.  The same
12562908d778ab3e244900c310974e1fc1c69066e450James Bottomley * logic applies to asd_post_ascb_list().
12572908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
12582908d778ab3e244900c310974e1fc1c69066e450James Bottomleyint asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
12592908d778ab3e244900c310974e1fc1c69066e450James Bottomley		       int num)
12602908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
12612908d778ab3e244900c310974e1fc1c69066e450James Bottomley	unsigned long flags;
12622908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12632908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
12642908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_swap_head_scb(asd_ha, ascb);
12652908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_ha->seq.scbpro += num;
12662908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
12672908d778ab3e244900c310974e1fc1c69066e450James Bottomley	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
12682908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12692908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
12702908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
12712908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12722908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- LED ---------- */
12732908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12742908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
12752908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_turn_led -- turn on/off an LED
12762908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
12772908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @phy_id: the PHY id whose LED we want to manupulate
12782908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @op: 1 to turn on, 0 to turn off
12792908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
12802908d778ab3e244900c310974e1fc1c69066e450James Bottomleyvoid asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
12812908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
12822908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (phy_id < ASD_MAX_PHYS) {
12832908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
12842908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (op)
12852908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v |= LEDPOL;
12862908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else
12872908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v &= ~LEDPOL;
12882908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
12892908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
12902908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
12912908d778ab3e244900c310974e1fc1c69066e450James Bottomley
12922908d778ab3e244900c310974e1fc1c69066e450James Bottomley/**
12932908d778ab3e244900c310974e1fc1c69066e450James Bottomley * asd_control_led -- enable/disable an LED on the board
12942908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @asd_ha: pointer to host adapter structure
12952908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @phy_id: integer, the phy id
12962908d778ab3e244900c310974e1fc1c69066e450James Bottomley * @op: integer, 1 to enable, 0 to disable the LED
12972908d778ab3e244900c310974e1fc1c69066e450James Bottomley *
12982908d778ab3e244900c310974e1fc1c69066e450James Bottomley * First we output enable the LED, then we set the source
12992908d778ab3e244900c310974e1fc1c69066e450James Bottomley * to be an external module.
13002908d778ab3e244900c310974e1fc1c69066e450James Bottomley */
13012908d778ab3e244900c310974e1fc1c69066e450James Bottomleyvoid asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
13022908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
13032908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (phy_id < ASD_MAX_PHYS) {
13042908d778ab3e244900c310974e1fc1c69066e450James Bottomley		u32 v;
13052908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13062908d778ab3e244900c310974e1fc1c69066e450James Bottomley		v = asd_read_reg_dword(asd_ha, GPIOOER);
13072908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (op)
13082908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v |= (1 << phy_id);
13092908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else
13102908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v &= ~(1 << phy_id);
13112908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_write_reg_dword(asd_ha, GPIOOER, v);
13122908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13132908d778ab3e244900c310974e1fc1c69066e450James Bottomley		v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
13142908d778ab3e244900c310974e1fc1c69066e450James Bottomley		if (op)
13152908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v |= (1 << phy_id);
13162908d778ab3e244900c310974e1fc1c69066e450James Bottomley		else
13172908d778ab3e244900c310974e1fc1c69066e450James Bottomley			v &= ~(1 << phy_id);
13182908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
13192908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
13202908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
13212908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13222908d778ab3e244900c310974e1fc1c69066e450James Bottomley/* ---------- PHY enable ---------- */
13232908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13242908d778ab3e244900c310974e1fc1c69066e450James Bottomleystatic int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
13252908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
13262908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_phy *phy = &asd_ha->phys[phy_id];
13272908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13282908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
13292908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
13302908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   HOTPLUG_DELAY_TIMEOUT);
13312908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13322908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* Get defaults from manuf. sector */
13332908d778ab3e244900c310974e1fc1c69066e450James Bottomley	/* XXX we need defaults for those in case MS is broken. */
13342908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
13352908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   phy->phy_desc->phy_control_0);
13362908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
13372908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   phy->phy_desc->phy_control_1);
13382908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
13392908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   phy->phy_desc->phy_control_2);
13402908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
13412908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   phy->phy_desc->phy_control_3);
13422908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13432908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
13442908d778ab3e244900c310974e1fc1c69066e450James Bottomley			    ASD_COMINIT_TIMEOUT);
13452908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13462908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
13472908d778ab3e244900c310974e1fc1c69066e450James Bottomley			   phy->id_frm_tok->dma_handle);
13482908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13492908d778ab3e244900c310974e1fc1c69066e450James Bottomley	asd_control_led(asd_ha, phy_id, 1);
13502908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13512908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return 0;
13522908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
13532908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13542908d778ab3e244900c310974e1fc1c69066e450James Bottomleyint asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
13552908d778ab3e244900c310974e1fc1c69066e450James Bottomley{
13562908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u8  phy_m;
13572908d778ab3e244900c310974e1fc1c69066e450James Bottomley	u8  i;
13582908d778ab3e244900c310974e1fc1c69066e450James Bottomley	int num = 0, k;
13592908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *ascb;
13602908d778ab3e244900c310974e1fc1c69066e450James Bottomley	struct asd_ascb *ascb_list;
13612908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13622908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!phy_mask) {
1363cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison		asd_printk("%s called with phy_mask of 0!?\n", __func__);
13642908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return 0;
13652908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
13662908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13672908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for_each_phy(phy_mask, phy_m, i) {
13682908d778ab3e244900c310974e1fc1c69066e450James Bottomley		num++;
13692908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_enable_phy(asd_ha, i);
13702908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
13712908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13722908d778ab3e244900c310974e1fc1c69066e450James Bottomley	k = num;
13732908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
13742908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (!ascb_list) {
13752908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_printk("no memory for control phy ascb list\n");
13762908d778ab3e244900c310974e1fc1c69066e450James Bottomley		return -ENOMEM;
13772908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
13782908d778ab3e244900c310974e1fc1c69066e450James Bottomley	num -= k;
13792908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13802908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ascb = ascb_list;
13812908d778ab3e244900c310974e1fc1c69066e450James Bottomley	for_each_phy(phy_mask, phy_m, i) {
13822908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_build_control_phy(ascb, i, ENABLE_PHY);
13832908d778ab3e244900c310974e1fc1c69066e450James Bottomley		ascb = list_entry(ascb->list.next, struct asd_ascb, list);
13842908d778ab3e244900c310974e1fc1c69066e450James Bottomley	}
13852908d778ab3e244900c310974e1fc1c69066e450James Bottomley	ASD_DPRINTK("posting %d control phy scbs\n", num);
13862908d778ab3e244900c310974e1fc1c69066e450James Bottomley	k = asd_post_ascb_list(asd_ha, ascb_list, num);
13872908d778ab3e244900c310974e1fc1c69066e450James Bottomley	if (k)
13882908d778ab3e244900c310974e1fc1c69066e450James Bottomley		asd_ascb_free_list(ascb_list);
13892908d778ab3e244900c310974e1fc1c69066e450James Bottomley
13902908d778ab3e244900c310974e1fc1c69066e450James Bottomley	return k;
13912908d778ab3e244900c310974e1fc1c69066e450James Bottomley}
1392