All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] pm8001: support HDA (flashless) mode
@ 2012-04-27 17:10 Mark Salyzyn
  2012-04-28  1:06 ` Jack Wang
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Mark Salyzyn @ 2012-04-27 17:10 UTC (permalink / raw)
  To: linux-scsi
  Cc: Mark Salyzyn, Jack Wang, James Bottomley, lindar_liu,
	于爱华,
	john_gong

[-- Attachment #1: Type: text/plain, Size: 1518 bytes --]

The pm8001 can be delivered as a standalone product with flash-programmed
firmware images, or without the flash present requiring the driver to upload
the images into the chip's RAM and then run. This is called HDA mode.

We add support for this firmware upload in the enclosed patch. We try some
basic initialization checks of the Firmware, and if it appears dead, we make
the assumption the adapter must in-fact be halted in this HDA mode. The
Firmware images themselves have not been cleared for open-release by PMC, but
they are available in OpenSolaris <hint hint>. PMC's rationalization for not
wanting an open-release of the Firmware Images is that they do not want to
take support calls except from paying OEMs (such as Xyratex) that are embedding
PMC product into the motherboards and thus may have a tested combination of
Firmware and Hardware. Please respect this sentiment. Images are expected in:

/lib/firmware/aap1img.bin
/lib/firmware/ilaimg.bin
/lib/firmware/iopimg.bin
/lib/firmware/istrimg.bin

using the exact same naming convention as PMC and in OpenSolaris (and its
followon children) for these image files.

Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>

 drivers/scsi/pm8001/pm8001_hwi.c  |  584 +++++++++++++++++++++++++++++++++++---
 drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
 drivers/scsi/pm8001/pm8001_init.c |   30 +
 drivers/scsi/pm8001/pm8001_sas.h  |    3 
 4 files changed, 613 insertions(+), 41 deletions(-)

Please see enclosed attachment


[-- Attachment #2: pm8001-hda.patch --]
[-- Type: application/octet-stream, Size: 25179 bytes --]

The pm8001 can be delivered as a standalone product with flash-programmed
firmware images, or without the flash present requiring the driver to upload
the images into the chip's RAM and then run. This is called HDA mode.

We add support for this firmware upload in the enclosed patch. We try some
basic initialization checks of the Firmware, and if it appears dead, we make
the assumption the adapter must in-fact be halted in this HDA mode. The
Firmware images themselves have not been cleared for open-release by PMC, but
they are available in OpenSolaris <hint hint>. PMC's rationalization for not
wanting an open-release of the Firmware Images is that they do not want to
take support calls except from paying OEMs (such as Xyratex) that are embedding
PMC product into the motherboards and thus may have a tested combination of
Firmware and Hardware. Please respect this sentiment. Images are expected in:

/lib/firmware/aap1img.bin
/lib/firmware/ilaimg.bin
/lib/firmware/iopimg.bin
/lib/firmware/istrimg.bin

using the exact same naming convention as PMC and in OpenSolaris (and its
followon children) for these image files.

Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>

 drivers/scsi/pm8001/pm8001_hwi.c  |  584 +++++++++++++++++++++++++++++++++++---
 drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
 drivers/scsi/pm8001/pm8001_init.c |   30 +
 drivers/scsi/pm8001/pm8001_sas.h  |    3 
 4 files changed, 613 insertions(+), 41 deletions(-)

diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 8477df4..25c733c 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -37,11 +37,13 @@
  * POSSIBILITY OF SUCH DAMAGES.
  *
  */
- #include <linux/slab.h>
- #include "pm8001_sas.h"
- #include "pm8001_hwi.h"
- #include "pm8001_chips.h"
- #include "pm8001_ctl.h"
+#include <linux/slab.h>
+#include "pm8001_sas.h"
+#include "pm8001_hwi.h"
+#include "pm8001_chips.h"
+#include "pm8001_ctl.h"
+
+#include <linux/firmware.h>
 
 /**
  * read_main_config_table - read the configure table and save it.
@@ -63,6 +65,9 @@ static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha)
 		pm8001_mr32(address, MAIN_OBQ_OFFSET);
 	pm8001_ha->main_cfg_tbl.hda_mode_flag	=
 		pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET);
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("MAIN_HDA_FLAGS = 0x%x\n",
+			pm8001_ha->main_cfg_tbl.hda_mode_flag));
 
 	/* read analog Setting offset from the configuration table */
 	pm8001_ha->main_cfg_tbl.anolog_setup_table_offset =
@@ -597,6 +602,484 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
 		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20);
 }
 
+static void pm8001_hda_send_cmd(struct pm8001_hba_info *pm8001_ha,
+				u32 arg_array[], u32 num_args, u32 cmd)
+{
+	u32	reg;
+	u32	i;
+
+	for (i = 0; i < num_args; i++)
+		pm8001_cw32(pm8001_ha, 3, HDA_CMD_OFFSET+(i*4), arg_array[i]);
+
+	reg = pm8001_cr32(pm8001_ha, 3, HDA_CMD_OFFSET+28);
+	reg = (reg & HDA_SEQ_ID_BITS) >> 16;
+	if (reg == 0xff)
+		reg = 0;
+	reg++;
+	reg = ((HDA_C_PA << 24) | (reg << 16) |  cmd);
+	pm8001_cw32(pm8001_ha, 3, HDA_CMD_OFFSET+28, reg);
+}
+
+static u32 pm8001_hda_recv_rsp(struct pm8001_hba_info *pm8001_ha, u32 cmd)
+{
+	u32	rsp;
+	u32	i = 0;
+
+	do {
+		mdelay(10);
+		rsp = pm8001_cr32(pm8001_ha, 3, HDA_CMD_OFFSET+28);
+		rsp = rsp & HDA_CODE_BITS;
+
+		switch (cmd) {
+		case HDAC_CMD_EXEC:
+			if (rsp == HDA_RSP_EXEC)
+				return 1;
+			if (rsp == HDA_RSP_BAD_IMG)
+				return 0;
+			if (rsp == HDA_RSP_BAD_CMD)
+				return 0;
+			break;
+		}
+		i++;
+	} while (i < 200);
+
+	return 1;
+}
+
+static u32 pm8001_bar4_cpy(struct pm8001_hba_info *pm8001_ha,
+	u32 base, u32 offset, const unsigned char array[], u32 alen)
+{
+	u32	dbase;
+	u32	doffset;
+	u32	*larray;
+	u32	val;
+	u32	csize;
+	u32	wc;
+	u32	i = 0;
+	unsigned long flags;
+
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("alen = 0x%x\n", alen));
+
+	dbase = (base+offset) & MB3_SHIFT_MASK;
+	doffset = offset & MB3_OFFSET_MASK;
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	do {
+		if (-1 == pm8001_bar4_shift(pm8001_ha, dbase)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			return 0;
+		}
+
+		if ((doffset+alen) > SIZE_64KB)
+			csize = SIZE_64KB - doffset;
+		else
+			csize = alen;
+
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR dbase = 0x%x\n", dbase));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR doffset = 0x%x\n", doffset));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR size = 0x%x\n", csize));
+
+		wc = ((csize % 4) > 0) ? ((csize / 4) + 1) : (csize / 4);
+		larray = (u32 *)array;
+		for (i = 0; i < wc; i++) {
+			val = larray[i];
+			pm8001_cw32(pm8001_ha, 2, (doffset + (i*4)), val);
+		}
+
+		alen -= csize;
+		dbase += SIZE_64KB;
+		doffset = 0;
+		array = array + csize;
+	} while (alen != 0);
+
+	if (-1 == pm8001_bar4_shift(pm8001_ha, 0x0)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+
+	return 1;
+}
+
+static u32 pm8001_bar4_cpy_big(struct pm8001_hba_info *pm8001_ha,
+	u32 base, u32 offset, const unsigned char array[], u32 alen)
+{
+	u32	dbase;
+	u32	doffset;
+	u32	*larray;
+	u32	val;
+	u32	csize;
+	u32	wc;
+	u32	i = 0;
+	u8 *local_buffer = NULL;
+	unsigned long flags;
+
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("alen = 0x%x\n", alen));
+
+	dbase = (base+offset) & MB3_SHIFT_MASK;
+	doffset = offset & MB3_OFFSET_MASK;
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	do {
+		if (-1 == pm8001_bar4_shift(pm8001_ha, dbase)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			return 0;
+		}
+
+		if ((doffset+alen) > SIZE_64KB)
+			csize = SIZE_64KB - doffset;
+		else
+			csize = alen;
+
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR dbase = 0x%x\n", dbase));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR doffset = 0x%x\n", doffset));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR size = 0x%x\n", csize));
+
+		wc = ((csize % 4) > 0) ? ((csize / 4) + 1) : (csize / 4);
+		local_buffer = kmalloc(csize, GFP_KERNEL);
+		if (local_buffer != NULL)
+			memcpy(local_buffer, array, csize);
+		larray = (u32 *)local_buffer;
+		for (i = 0; i < wc; i++) {
+			val = larray[i];
+			pm8001_cw32(pm8001_ha, 2, (doffset + (i*4)), val);
+		}
+		kfree(local_buffer);
+		alen -= csize;
+		dbase += SIZE_64KB;
+		doffset = 0;
+		array = array + csize;
+	} while (alen != 0);
+
+	if (-1 == pm8001_bar4_shift(pm8001_ha, 0x0)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+
+	return 1;
+}
+
+
+static int pm8001_ishdar_idle(struct pm8001_hba_info *pm8001_ha)
+{
+	u32     hdaw;
+	u32     pcilogic;
+
+	pcilogic = get_pci_bar_index(0x24);
+
+	hdaw = pm8001_cr32(pm8001_ha, pcilogic, HDA_RSP_OFFSET+28);
+	if ((((hdaw & HDA_PA_BITS) >> 24) == HDA_R_PA)
+	 && ((hdaw & HDA_CODE_BITS) == HDA_RSP_IDLE))
+		return 1;
+
+	return 0;
+}
+
+static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha);
+
+/* Catch-22, this is called before chip initialization, values may change */
+static int __devinit pm8001_chip_in_hda_mode(struct pm8001_hba_info *pm8001_ha)
+{
+	u32	data;
+
+	if (!pm8001_ha->main_cfg_tbl_addr)
+		init_pci_device_addresses(pm8001_ha);
+	if (!pm8001_ha->main_cfg_tbl_addr)
+		return 0;
+	if (mpi_uninit_check(pm8001_ha) != 0) {
+		/* Must be sick, must be in HDA mode? */
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("MPI state not ready, in HDA mode?\n"));
+		return 1;
+	}
+	/* check the firmware status */
+	if (-1 == check_fw_ready(pm8001_ha)) {
+		/* Must be sick, must be in HDA mode? */
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("Firmware is not ready, in HDA mode?\n"));
+		return 1;
+	}
+	if (!pm8001_ha->main_cfg_tbl.hda_mode_flag)
+		read_main_config_table(pm8001_ha);
+	if (!pm8001_ha->main_cfg_tbl.hda_mode_flag) {
+		/* Must be sick, must be in HDA mode? */
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("HDA mode offset bad, in HDA mode?\n"));
+		return 1;
+	}
+	data = pm8001_mr32(
+		pm8001_ha->main_cfg_tbl_addr,
+		pm8001_ha->main_cfg_tbl.hda_mode_flag);
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("*MAIN_HDA_FLAGS = 0x%x\n", data));
+	return data & 0x4;
+}
+
+static int
+pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature);
+
+static int pm8001_chip_hda_mode(struct pm8001_hba_info *pm8001_ha)
+{
+	int	i = 0;
+	u32	arga[6];
+	u32	reg;
+	u32	aap1_offset;
+	u32	fw_offset;
+	u32	pad1;
+	u32	pad2;
+	u8 *istr_buffer = NULL;
+	u32 istr_length = 0;
+	u8 *ila_buffer = NULL;
+	u32 ila_length = 0;
+	u32 aap1_length = 0;
+	u32 iop_length = 0;
+	u8 firmware_released = true;
+
+	/*get initial string image*/
+	if (request_firmware(&pm8001_ha->fw_image, "istrimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get istrimg.bin\n");
+		goto err_out_hda;
+	}
+	istr_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get istrimg.bin, length is %x\n", istr_length);
+	istr_buffer = kmalloc(pm8001_ha->fw_image->size, GFP_KERNEL);
+	if (istr_buffer == NULL) {
+		release_firmware(pm8001_ha->fw_image);
+		goto err_out_hda;
+	}
+
+	memcpy(istr_buffer, pm8001_ha->fw_image->data,
+		pm8001_ha->fw_image->size);
+	release_firmware(pm8001_ha->fw_image);
+
+	/*Get ILA image*/
+	if (request_firmware(&pm8001_ha->fw_image, "ilaimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get ilaimg.bin\n");
+		goto err_out_hda;
+	}
+
+	ila_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get ilaimg.bin, length is %x\n", ila_length);
+	ila_buffer = kmalloc(pm8001_ha->fw_image->size, GFP_KERNEL);
+	if (ila_buffer == NULL) {
+		release_firmware(pm8001_ha->fw_image);
+		goto err_out_hda;
+	}
+
+	memcpy(ila_buffer, pm8001_ha->fw_image->data,
+		pm8001_ha->fw_image->size);
+	release_firmware(pm8001_ha->fw_image);
+
+	/*get aap1 image*/
+	if (request_firmware(&pm8001_ha->fw_image, "aap1img.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get aap1img.bin\n");
+		goto err_out_hda;
+	}
+	aap1_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get aap1img.bin, length is %x\n", aap1_length);
+
+	firmware_released = false;
+
+	/* Try soft reset until it goes into HDA mode */
+	pm8001_chip_soft_rst(pm8001_ha, SPC_HDASOFT_RESET_SIGNATURE);
+	mdelay(10);
+	if (!pm8001_ishdar_idle(pm8001_ha)) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("SPC_HDASOFT_RESET: failed!\n"));
+		goto err_out_hda;
+	}
+
+	/* HDA Mode - Clear ODMR and ODCR */
+	pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
+	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
+
+	/* Step 1: Poll HDA_RSP_IDLE - HDA mode */
+	i = 0;
+	do {
+		mdelay(10);
+		if (pm8001_ishdar_idle(pm8001_ha))
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("HDA Mode: Timeout!\n")); /* 2 sec */
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("HDA Mode!\n"));
+
+	/* Step 2: Push the init string to 0x0047E000 & data compare */
+	pm8001_printk("istrimage length is %x\n", istr_length);
+	if (!pm8001_bar4_cpy(pm8001_ha, GSM_HDA_ILA_STR_BASE,
+			GSM_ILA_STR_OFFSET, istr_buffer, istr_length))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("ILA Str cpy done!\n"));
+
+	/* Tell FW ISTR is ready */
+	reg = (ILA_HDA_ISTR_IMG_DONE << 24) | istr_length;
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+	/* Step 3: Write the HDA mode SoftReset signature */
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0,
+		SPC_HDASOFT_RESET_SIGNATURE);
+
+	/* Step 4: Push the ILA image to 0x00400000 */
+	arga[1] = ila_length;
+	if (!pm8001_bar4_cpy(pm8001_ha, GSM_HDA_ILA_BASE, GSM_HDA_ILA_OFFSET,
+			ila_buffer, ila_length))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("ILA  cpy done!\n"));
+
+	/* Step 5: Tell boot ROM to authenticate ILA and execute it */
+	arga[0] = 0;
+	pm8001_hda_send_cmd(pm8001_ha, arga, 2, HDAC_CMD_EXEC);
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("CMD EXEC sent!\n"));
+
+	/*
+	 * Step 6: Checking response status from boot ROM,
+	 *         HDAR_EXEC (good), HDAR_BAD_CMD and HDAR_BAD_IMG
+	 */
+	if (!pm8001_hda_recv_rsp(pm8001_ha, HDAC_CMD_EXEC))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("CMD EXEC rsp ok!\n"));
+
+	/* Step 7: Poll ILAHDA_AAP1IMGGET/Offset in MSGU Scratchpad 0 */
+	/* Check MSGU Scratchpad 1 [1,0] == 00 */
+	i = 0;
+	do {
+		mdelay(10);
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+		aap1_offset = reg & ~SCRATCH_PAD0_STATE_MASK;
+		reg = reg >> 24;
+		if (reg == ILA_HDA_AAP1_IMG_GET)
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("APP1_IMG_GET Poll timeout !\n"));
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("scratch pad 1 = 0x%x\n", reg));
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("scratch pad 2 = 0x%x\n", reg));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("APP1 img get ok!\n"));
+
+	/* Step 8: Copy AAP1 image, update the Host Scratchpad 3 */
+	reg = (ILA_HDA_AAP1_IMG_DONE << 24) | aap1_length;
+	if (!pm8001_bar4_cpy_big(pm8001_ha, GSM_HDA_ILA_BASE, aap1_offset,
+			pm8001_ha->fw_image->data, aap1_length)) {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+		goto err_out_hda;
+	} else {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("APP1  cpy done!\n"));
+
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+
+	/*Get IOP image*/
+	if (request_firmware(&pm8001_ha->fw_image, "iopimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get istrimg.bin\n");
+		goto err_out_hda;
+	} else {
+		iop_length = pm8001_ha->fw_image->size;
+		pm8001_printk("Get iopimg.bin, length is %x\n", iop_length);
+		firmware_released = false;
+	}
+
+	/* Step 9: Poll ILAHDA_IOPIMGGET/Offset in MSGU Scratchpad 0 */
+	i = 0;
+	do {
+		mdelay(10);
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+		fw_offset = reg & ~SCRATCH_PAD0_STATE_MASK;
+		reg = reg >> 24;
+		if (reg == ILA_HDA_IOP_IMG_GET)
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("IOP_IMG_GET Poll timeout !\n"));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("IOP img get ok!\n"));
+
+	/* Step 10: Copy IOP image, update the Host Scratchpad 3 */
+	reg = (ILA_HDA_IOP_IMG_DONE << 24) | iop_length;
+	if (!pm8001_bar4_cpy_big(pm8001_ha, GSM_HDA_ILA_BASE, fw_offset,
+			pm8001_ha->fw_image->data, iop_length)) {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+		goto err_out_hda;
+	} else {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("IOP  cpy done!\n"));
+
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+	/* Clear the signature */
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, 0);
+
+	/* step 11: wait for the FW and IOP to get ready - 1 sec timeout */
+	/* Wait for the SPC Configuration Table to be ready */
+	i = 0;
+	do {
+		mdelay(10);
+		pad1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+		if (pad1 & SCRATCH_PAD1_RDY) {
+			pad2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+			if (pad2 & SCRATCH_PAD2_RDY)
+				break;
+		}
+		i++;
+	} while (i < 200);
+
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("PAD 1 & 2 not Rdy !\n"));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("HDA Mode Complete!\n"));
+
+	kfree(istr_buffer);
+	kfree(ila_buffer);
+	if (firmware_released == false)
+		release_firmware(pm8001_ha->fw_image);
+
+	return 1;
+
+err_out_hda:
+	kfree(istr_buffer);
+	kfree(ila_buffer);
+	if (firmware_released == false)
+		release_firmware(pm8001_ha->fw_image);
+
+	return 0;
+}
+
 /**
  * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
  * @pm8001_ha: our hba card information
@@ -704,40 +1187,60 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("Firmware is ready for reset .\n"));
 	} else {
-		unsigned long flags;
-		/* Trigger NMI twice via RB6 */
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
-		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("Shift Bar4 to 0x%x failed\n",
-					RB6_ACCESS_REG));
-			return -1;
-		}
-		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
-			RB6_MAGIC_NUMBER_RST);
-		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST);
-		/* wait for 100 ms */
-		mdelay(100);
-		regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
-			SCRATCH_PAD2_FWRDY_RST;
-		if (regVal != SCRATCH_PAD2_FWRDY_RST) {
-			regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
-			regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("TIMEOUT:MSGU_SCRATCH_PAD1"
-				"=0x%x, MSGU_SCRATCH_PAD2=0x%x\n",
-				regVal1, regVal2));
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("SCRATCH_PAD0 value = 0x%x\n",
-				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)));
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
-				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+		if (pm8001_ishdar_idle(pm8001_ha)) {
+			/*
+			 *	For customers wants to do soft reset even the
+			 * chip is already in HDA mode
+			 *
+			 * Do not need to trigger RB6 twice
+			 */
+			;
+		} else {
+			unsigned long flags;
+			/* Trigger NMI twice via RB6 */
+			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			if (-1 == pm8001_bar4_shift(pm8001_ha,
+					RB6_ACCESS_REG)) {
+				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("Shift Bar4 to 0x%x "
+						"failed\n",
+						RB6_ACCESS_REG));
+				return -1;
+			}
+			pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
+				RB6_MAGIC_NUMBER_RST);
+			pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
+				RB6_MAGIC_NUMBER_RST);
+			/* wait for 100 ms */
+			mdelay(100);
+			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
+				SCRATCH_PAD2_FWRDY_RST;
+			if (regVal != SCRATCH_PAD2_FWRDY_RST) {
+				regVal1 = pm8001_cr32(pm8001_ha, 0,
+					MSGU_SCRATCH_PAD_1);
+				regVal2 = pm8001_cr32(pm8001_ha, 0,
+					MSGU_SCRATCH_PAD_2);
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("TIMEOUT:"
+						"MSGU_SCRATCH_PAD1=0x%x, "
+						"MSGU_SCRATCH_PAD2=0x%x\n",
+						regVal1, regVal2));
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("SCRATCH_PAD0 "
+						"value = 0x%x\n",
+						pm8001_cr32(pm8001_ha, 0,
+							MSGU_SCRATCH_PAD_0)));
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("SCRATCH_PAD3 "
+						"value = 0x%x\n",
+						pm8001_cr32(pm8001_ha, 0,
+							MSGU_SCRATCH_PAD_3)));
+				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				return -1;
+			}
 			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
-			return -1;
 		}
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	}
 	return 0;
 }
@@ -1009,7 +1512,10 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
 
 	/* step 14: delay 10 usec - Normal Mode */
-	udelay(10);
+	if (signature == SPC_SOFT_RESET_SIGNATURE)
+		udelay(10);
+	else
+		mdelay(200);
 	/* check Soft Reset Normal mode or Soft Reset HDA mode */
 	if (signature == SPC_SOFT_RESET_SIGNATURE) {
 		/* step 15 (Normal Mode): wait until scratch pad1 register
@@ -4683,6 +5189,8 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
 
 const struct pm8001_dispatch pm8001_8001_dispatch = {
 	.name			= "pmc8001",
+	.chip_in_hda_mode	= pm8001_chip_in_hda_mode,
+	.chip_hda_mode		= pm8001_chip_hda_mode,
 	.chip_init		= pm8001_chip_init,
 	.chip_soft_rst		= pm8001_chip_soft_rst,
 	.chip_rst		= pm8001_hw_chip_rst,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 1a4611e..2f178e0 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -855,6 +855,16 @@ struct set_dev_state_resp {
 #define MSIX_INTERRUPT_DISABLE		0x1
 #define MSIX_INTERRUPT_ENABLE		0x0
 
+/* ILA codes in MSGU Scratchpad 0 */
+#define ILA_HDA_IOP_IMG_GET              0x10
+#define ILA_HDA_AAP1_IMG_GET             0x11
+#define ILA_HDA_AAP2_IMG_GET             0x12
+#define ILA_HDA_EXITGOOD                 0x1F
+#define ILA_HDA_IOP_IMG_DONE             0x80
+#define ILA_HDA_AAP1_IMG_DONE            0x81
+#define ILA_HDA_ISTR_IMG_DONE            0x83
+
+#define SCRATCH_PAD0_STATE_MASK		0xFF000000
 
 /* state definition for Scratch Pad1 register */
 #define SCRATCH_PAD1_POR		0x00  /* power on reset state */
@@ -952,8 +962,10 @@ struct set_dev_state_resp {
 #define PCIE_ERROR_INTERRUPT_ENABLE	0x003048
 #define PCIE_ERROR_INTERRUPT		0x00304C
 /* signature definition for host scratch pad0 register */
-#define SPC_SOFT_RESET_SIGNATURE	0x252acbcd
 /* Signature for Soft Reset */
+#define SPC_SOFT_RESET_SIGNATURE	0x252acbcd
+/* Signature for HDA Soft Reset without PCIe resetting */
+#define SPC_HDASOFT_RESET_SIGNATURE	0xa5aa27d7
 
 /* SPC Reset register - BAR4(0x20), BAR2(win) (need dynamic mapping) */
 #define SPC_REG_RESET			0x000000/* reset register */
@@ -987,6 +999,14 @@ struct set_dev_state_resp {
 #define MBIC_AAP1_ADDR_BASE		0x060000
 #define MBIC_IOP_ADDR_BASE		0x070000
 #define GSM_ADDR_BASE			0x0700000
+#define GSM_HDA_ILA_STR_BASE            0x470000
+#define GSM_ILA_STR_OFFSET              0xE000
+#define GSM_HDA_ILA_BASE                0x400000
+#define GSM_HDA_ILA_OFFSET              0x0
+#define SIZE_64KB                       0x00010000
+#define MB3_SHIFT_MASK                  0xFFFF0000
+#define MB3_OFFSET_MASK                 0x0000FFFF
+
 /* Dynamic map through Bar4 - 0x00700000 */
 #define GSM_CONFIG_RESET		0x00000000
 #define RAM_ECC_DB_ERR			0x00000018
@@ -998,10 +1018,23 @@ struct set_dev_state_resp {
 #define GSM_WRITE_DATA_PARITY_CHECK	0x00000048
 
 #define RB6_ACCESS_REG			0x6A0000
-#define HDAC_EXEC_CMD			0x0002
+#define HDA_CMD_OFFSET			0xfec0
+#define HDA_RSP_OFFSET			0xfee0
+#define HDAC_CMD_BUF_INFO		0x0001
+#define HDAC_CMD_EXEC			0x0002
+#define HDAC_CMD_RESET			0x0003
 #define HDA_C_PA			0xcb
+#define HDA_R_PA			0xdb
+#define HDA_PA_BITS			0xff000000
 #define HDA_SEQ_ID_BITS			0x00ff0000
+#define HDA_CODE_BITS			0x0000ffff
 #define HDA_GSM_OFFSET_BITS		0x00FFFFFF
+#define HDA_RSP_BUF_INFO		0x8001
+#define HDA_RSP_IDLE			0x8002
+#define HDA_RSP_BAD_IMG			0x8003
+#define HDA_RSP_BAD_CMD			0x8004
+#define HDA_RSP_INTL_ERR		0x8005
+#define HDA_RSP_EXEC			0x8006
 #define MBIC_AAP1_ADDR_BASE		0x060000
 #define MBIC_IOP_ADDR_BASE		0x070000
 #define GSM_ADDR_BASE			0x0700000
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 36efaa7..db5bd77 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_chips.h"
+#include "pm8001_hwi.h"
 
 static struct scsi_transport_template *pm8001_stt;
 
@@ -669,8 +670,35 @@ static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
 		rc = -ENOMEM;
 		goto err_out_free;
 	}
+	/*
+	 * Make sure we have at least a sane region 0
+	 *
+	 * We do this here because a failure in pm8001_pci_alloc
+	 * is just interpreted as a memory allocation failure.
+	 */
+	if (pm8001_ha->io_mem[0].memvirtaddr == NULL
+	 || pm8001_ha->io_mem[0].memsize < (1 << 15)) {
+		printk(KERN_ERR "BAR0 access bad: %p,%x\n",
+			pm8001_ha->io_mem[0].memvirtaddr,
+			pm8001_ha->io_mem[0].memsize);
+		rc = -ENXIO;
+		goto err_out_free;
+	}
 	list_add_tail(&pm8001_ha->list, &hba_list);
-	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+
+	/* HDA SEEPROM Force HDA Mode */
+	if (PM8001_CHIP_DISP->chip_in_hda_mode(pm8001_ha)) {
+		rc = PM8001_CHIP_DISP->chip_hda_mode(pm8001_ha);
+		if (!rc) {
+			rc = -EBUSY;
+			goto err_out_ha_free;
+		}
+		pm8001_ha->rst_signature = SPC_HDASOFT_RESET_SIGNATURE;
+	} else {
+		PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha,
+			SPC_SOFT_RESET_SIGNATURE);
+		pm8001_ha->rst_signature = SPC_SOFT_RESET_SIGNATURE;
+	}
 	rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
 	if (rc)
 		goto err_out_ha_free;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 1100820..4b7f2e0 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -130,6 +130,8 @@ struct pm8001_ioctl_payload {
 
 struct pm8001_dispatch {
 	char *name;
+	int (*chip_in_hda_mode)(struct pm8001_hba_info *pm8001_ha);
+	int (*chip_hda_mode)(struct pm8001_hba_info *pm8001_ha);
 	int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
 	int (*chip_soft_rst)(struct pm8001_hba_info *pm8001_ha, u32 signature);
 	void (*chip_rst)(struct pm8001_hba_info *pm8001_ha);
@@ -384,6 +386,7 @@ struct pm8001_hba_info {
 	u32			logging_level;
 	u32			fw_status;
 	const struct firmware 	*fw_image;
+	u32			rst_signature;
 };
 
 struct pm8001_work {

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-27 17:10 [PATCH] pm8001: support HDA (flashless) mode Mark Salyzyn
@ 2012-04-28  1:06 ` Jack Wang
  2012-04-30 14:00   ` Mark Salyzyn
  2012-04-28  4:44 ` Re " Jack Wang
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: Jack Wang @ 2012-04-28  1:06 UTC (permalink / raw)
  To: 'Mark Salyzyn', linux-scsi
  Cc: 'James Bottomley', 'lindar_liu',
	'于爱华', 'john_gong'

Thanks Mark,

So how we get the bin images? PMCS only offer the converted c Header file
for this, we need users who want to use this function convert the header
file to bin file.

Patch need a little more time to look into, will comment back soon.

Jack


> 
> The pm8001 can be delivered as a standalone product with flash-programmed
> firmware images, or without the flash present requiring the driver to
upload
> the images into the chip's RAM and then run. This is called HDA mode.
> 
> We add support for this firmware upload in the enclosed patch. We try some
> basic initialization checks of the Firmware, and if it appears dead, we
make
> the assumption the adapter must in-fact be halted in this HDA mode. The
> Firmware images themselves have not been cleared for open-release by PMC,
but
> they are available in OpenSolaris <hint hint>. PMC's rationalization for
not
> wanting an open-release of the Firmware Images is that they do not want to
> take support calls except from paying OEMs (such as Xyratex) that are
embedding
> PMC product into the motherboards and thus may have a tested combination
of
> Firmware and Hardware. Please respect this sentiment. Images are expected
in:
> 
> /lib/firmware/aap1img.bin
> /lib/firmware/ilaimg.bin
> /lib/firmware/iopimg.bin
> /lib/firmware/istrimg.bin
> 
> using the exact same naming convention as PMC and in OpenSolaris (and its
> followon children) for these image files.
> 
> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
> 
>  drivers/scsi/pm8001/pm8001_hwi.c  |  584
> +++++++++++++++++++++++++++++++++++---
>  drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>  drivers/scsi/pm8001/pm8001_init.c |   30 +
>  drivers/scsi/pm8001/pm8001_sas.h  |    3
>  4 files changed, 613 insertions(+), 41 deletions(-)
> 
> Please see enclosed attachment
> 
> 
> ______________________________________________________________________
> This email may contain privileged or confidential information, which
should
> only be used for the purpose for which it was sent by Xyratex. No further
rights
> or licenses are granted to use such information. If you are not the
intended
> recipient of this message, please notify the sender by return and delete
it.
> You may not use, copy, disclose or rely on the information contained in
it.
> 
> Internet email is susceptible to data corruption, interception and
> unauthorised amendment for which Xyratex does not accept liability. While
we
> have taken reasonable precautions to ensure that this email is free of
viruses,
> Xyratex does not accept liability for the presence of any computer viruses
in
> this email, nor for any losses caused as a result of viruses.
> 
> Xyratex Technology Limited (03134912), Registered in England & Wales,
> Registered Office, Langstone Road, Havant, Hampshire, PO9 1SA.
> 
> The Xyratex group of companies also includes, Xyratex Ltd, registered in
> Bermuda, Xyratex International Inc, registered in California, Xyratex
> (Malaysia) Sdn Bhd registered in Malaysia, Xyratex Technology (Wuxi) Co
Ltd
> registered in The People's Republic of China and Xyratex Japan Limited
> registered in Japan.
> ______________________________________________________________________
> 
> 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re [PATCH] pm8001: support HDA (flashless) mode
  2012-04-27 17:10 [PATCH] pm8001: support HDA (flashless) mode Mark Salyzyn
  2012-04-28  1:06 ` Jack Wang
@ 2012-04-28  4:44 ` Jack Wang
  2012-04-30 13:43   ` Mark Salyzyn
  2012-04-28  6:07 ` Jack Wang
  2012-05-01 12:45 ` [PATCH] pm8001: support HDA (flashless) mode (take 2) Mark Salyzyn
  3 siblings, 1 reply; 12+ messages in thread
From: Jack Wang @ 2012-04-28  4:44 UTC (permalink / raw)
  To: 'Mark Salyzyn', linux-scsi
  Cc: 'James Bottomley', 'lindar_liu',
	'于爱华', 'john_gong'

-	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+
+	/* HDA SEEPROM Force HDA Mode */
+	if (PM8001_CHIP_DISP->chip_in_hda_mode(pm8001_ha)) {
+		rc = PM8001_CHIP_DISP->chip_hda_mode(pm8001_ha);
+		if (!rc) {
+			rc = -EBUSY;
+			goto err_out_ha_free;
+		}
+		pm8001_ha->rst_signature = SPC_HDASOFT_RESET_SIGNATURE;
+	} else {
+		PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha,
+			SPC_SOFT_RESET_SIGNATURE);
+		pm8001_ha->rst_signature = SPC_SOFT_RESET_SIGNATURE;
+	}

Here I think we'd better try normal mode first, then fail to HAD mode.

Jack

> 
> The pm8001 can be delivered as a standalone product with flash-programmed
> firmware images, or without the flash present requiring the driver to
upload
> the images into the chip's RAM and then run. This is called HDA mode.
> 
> We add support for this firmware upload in the enclosed patch. We try some
> basic initialization checks of the Firmware, and if it appears dead, we
make
> the assumption the adapter must in-fact be halted in this HDA mode. The
> Firmware images themselves have not been cleared for open-release by PMC,
but
> they are available in OpenSolaris <hint hint>. PMC's rationalization for
not
> wanting an open-release of the Firmware Images is that they do not want to
> take support calls except from paying OEMs (such as Xyratex) that are
embedding
> PMC product into the motherboards and thus may have a tested combination
of
> Firmware and Hardware. Please respect this sentiment. Images are expected
in:
> 
> /lib/firmware/aap1img.bin
> /lib/firmware/ilaimg.bin
> /lib/firmware/iopimg.bin
> /lib/firmware/istrimg.bin
> 
> using the exact same naming convention as PMC and in OpenSolaris (and its
> followon children) for these image files.
> 
> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
> 
>  drivers/scsi/pm8001/pm8001_hwi.c  |  584
> +++++++++++++++++++++++++++++++++++---
>  drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>  drivers/scsi/pm8001/pm8001_init.c |   30 +
>  drivers/scsi/pm8001/pm8001_sas.h  |    3
>  4 files changed, 613 insertions(+), 41 deletions(-)
> 
> Please see enclosed attachment



^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-27 17:10 [PATCH] pm8001: support HDA (flashless) mode Mark Salyzyn
  2012-04-28  1:06 ` Jack Wang
  2012-04-28  4:44 ` Re " Jack Wang
@ 2012-04-28  6:07 ` Jack Wang
  2012-04-30 13:49   ` Mark Salyzyn
  2012-05-01 12:45 ` [PATCH] pm8001: support HDA (flashless) mode (take 2) Mark Salyzyn
  3 siblings, 1 reply; 12+ messages in thread
From: Jack Wang @ 2012-04-28  6:07 UTC (permalink / raw)
  To: 'Mark Salyzyn', linux-scsi
  Cc: 'James Bottomley', 'lindar_liu',
	'于爱华', 'john_gong'


+	data = pm8001_mr32(
+		pm8001_ha->main_cfg_tbl_addr,
+		pm8001_ha->main_cfg_tbl.hda_mode_flag);
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("*MAIN_HDA_FLAGS = 0x%x\n", data));
+	return data & 0x4;

Here seems wrong, you may want to check the force hda bit? So you need to
read offset #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */

Jack


> 
> The pm8001 can be delivered as a standalone product with flash-programmed
> firmware images, or without the flash present requiring the driver to
upload
> the images into the chip's RAM and then run. This is called HDA mode.
> 
> We add support for this firmware upload in the enclosed patch. We try some
> basic initialization checks of the Firmware, and if it appears dead, we
make
> the assumption the adapter must in-fact be halted in this HDA mode. The
> Firmware images themselves have not been cleared for open-release by PMC,
but
> they are available in OpenSolaris <hint hint>. PMC's rationalization for
not
> wanting an open-release of the Firmware Images is that they do not want to
> take support calls except from paying OEMs (such as Xyratex) that are
embedding
> PMC product into the motherboards and thus may have a tested combination
of
> Firmware and Hardware. Please respect this sentiment. Images are expected
in:
> 
> /lib/firmware/aap1img.bin
> /lib/firmware/ilaimg.bin
> /lib/firmware/iopimg.bin
> /lib/firmware/istrimg.bin
> 
> using the exact same naming convention as PMC and in OpenSolaris (and its
> followon children) for these image files.
> 
> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
> 
>  drivers/scsi/pm8001/pm8001_hwi.c  |  584
> +++++++++++++++++++++++++++++++++++---
>  drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>  drivers/scsi/pm8001/pm8001_init.c |   30 +
>  drivers/scsi/pm8001/pm8001_sas.h  |    3
>  4 files changed, 613 insertions(+), 41 deletions(-)
> 
> Please see enclosed attachment



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Re [PATCH] pm8001: support HDA (flashless) mode
  2012-04-28  4:44 ` Re " Jack Wang
@ 2012-04-30 13:43   ` Mark Salyzyn
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Salyzyn @ 2012-04-30 13:43 UTC (permalink / raw)
  To: Jack Wang
  Cc: Mark Salyzyn, linux-scsi, 'James Bottomley',
	'lindar_liu', '于爱华',
	'john_gong'

If you look at the pm8001_chip_in_hda_mode test, it actually is doing some early stages of 'normal' mode initialization. The adapter in HDA mode fails at the mpi_uninit_check() (one of the first 'normal' mode operations), the remaining tests are additional stages, but in practice we actually have only seen the first one mpi_uninit_check() fail and thus switch to HDA mode by reporting the assumption that the adapter (must/may?) be in hda mode. 

There is a catch-22 in the later parts of the test, in that an Adapter in HDA mode is not doing anything, so it certainly can not report it is in this mode ;-/

Sincerely -- Mark Salyzyn

On Apr 28, 2012, at 12:44 AM, Jack Wang wrote:

> -	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
> +
> +	/* HDA SEEPROM Force HDA Mode */
> +	if (PM8001_CHIP_DISP->chip_in_hda_mode(pm8001_ha)) {
> +		rc = PM8001_CHIP_DISP->chip_hda_mode(pm8001_ha);
> +		if (!rc) {
> +			rc = -EBUSY;
> +			goto err_out_ha_free;
> +		}
> +		pm8001_ha->rst_signature = SPC_HDASOFT_RESET_SIGNATURE;
> +	} else {
> +		PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha,
> +			SPC_SOFT_RESET_SIGNATURE);
> +		pm8001_ha->rst_signature = SPC_SOFT_RESET_SIGNATURE;
> +	}
> 
> Here I think we'd better try normal mode first, then fail to HAD mode.
> 
> Jack
> 
>> 
>> The pm8001 can be delivered as a standalone product with flash-programmed
>> firmware images, or without the flash present requiring the driver to
> upload
>> the images into the chip's RAM and then run. This is called HDA mode.
>> 
>> We add support for this firmware upload in the enclosed patch. We try some
>> basic initialization checks of the Firmware, and if it appears dead, we
> make
>> the assumption the adapter must in-fact be halted in this HDA mode. The
>> Firmware images themselves have not been cleared for open-release by PMC,
> but
>> they are available in OpenSolaris <hint hint>. PMC's rationalization for
> not
>> wanting an open-release of the Firmware Images is that they do not want to
>> take support calls except from paying OEMs (such as Xyratex) that are
> embedding
>> PMC product into the motherboards and thus may have a tested combination
> of
>> Firmware and Hardware. Please respect this sentiment. Images are expected
> in:
>> 
>> /lib/firmware/aap1img.bin
>> /lib/firmware/ilaimg.bin
>> /lib/firmware/iopimg.bin
>> /lib/firmware/istrimg.bin
>> 
>> using the exact same naming convention as PMC and in OpenSolaris (and its
>> followon children) for these image files.
>> 
>> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
>> 
>> drivers/scsi/pm8001/pm8001_hwi.c  |  584
>> +++++++++++++++++++++++++++++++++++---
>> drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>> drivers/scsi/pm8001/pm8001_init.c |   30 +
>> drivers/scsi/pm8001/pm8001_sas.h  |    3
>> 4 files changed, 613 insertions(+), 41 deletions(-)
>> 
>> Please see enclosed attachment
> 
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-28  6:07 ` Jack Wang
@ 2012-04-30 13:49   ` Mark Salyzyn
  2012-04-30 16:56     ` Mark Salyzyn
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Salyzyn @ 2012-04-30 13:49 UTC (permalink / raw)
  To: Jack Wang
  Cc: Mark Salyzyn, linux-scsi, 'James Bottomley',
	'lindar_liu', '于爱华',
	'john_gong'

You are right ... however this code is 'never reached' since mpi_uninit_check() generally fails before this in the chip_in_hda_mode set of tests.

I instrumented up, on our HDA mode chip, we are seeing a value of ZERO in MAIN_HDA_FLAGS_OFFSET ... Ahh, the world of initializing hardware that is in an indeterminate (code not running) state ...

-- Mark

On Apr 28, 2012, at 2:07 AM, Jack Wang wrote:

> 
> +	data = pm8001_mr32(
> +		pm8001_ha->main_cfg_tbl_addr,
> +		pm8001_ha->main_cfg_tbl.hda_mode_flag);
> +	PM8001_INIT_DBG(pm8001_ha,
> +		pm8001_printk("*MAIN_HDA_FLAGS = 0x%x\n", data));
> +	return data & 0x4;
> 
> Here seems wrong, you may want to check the force hda bit? So you need to
> read offset #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
> 
> Jack
> 
> 
>> 
>> The pm8001 can be delivered as a standalone product with flash-programmed
>> firmware images, or without the flash present requiring the driver to
> upload
>> the images into the chip's RAM and then run. This is called HDA mode.
>> 
>> We add support for this firmware upload in the enclosed patch. We try some
>> basic initialization checks of the Firmware, and if it appears dead, we
> make
>> the assumption the adapter must in-fact be halted in this HDA mode. The
>> Firmware images themselves have not been cleared for open-release by PMC,
> but
>> they are available in OpenSolaris <hint hint>. PMC's rationalization for
> not
>> wanting an open-release of the Firmware Images is that they do not want to
>> take support calls except from paying OEMs (such as Xyratex) that are
> embedding
>> PMC product into the motherboards and thus may have a tested combination
> of
>> Firmware and Hardware. Please respect this sentiment. Images are expected
> in:
>> 
>> /lib/firmware/aap1img.bin
>> /lib/firmware/ilaimg.bin
>> /lib/firmware/iopimg.bin
>> /lib/firmware/istrimg.bin
>> 
>> using the exact same naming convention as PMC and in OpenSolaris (and its
>> followon children) for these image files.
>> 
>> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
>> 
>> drivers/scsi/pm8001/pm8001_hwi.c  |  584
>> +++++++++++++++++++++++++++++++++++---
>> drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>> drivers/scsi/pm8001/pm8001_init.c |   30 +
>> drivers/scsi/pm8001/pm8001_sas.h  |    3
>> 4 files changed, 613 insertions(+), 41 deletions(-)
>> 
>> Please see enclosed attachment
> 
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-28  1:06 ` Jack Wang
@ 2012-04-30 14:00   ` Mark Salyzyn
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Salyzyn @ 2012-04-30 14:00 UTC (permalink / raw)
  To: Jack Wang
  Cc: Mark Salyzyn, linux-scsi, 'James Bottomley',
	'lindar_liu', '于爱华',
	'john_gong'

PMC still does not like the images or firmware header files getting out willy-nilly, have not got free redistribution rights or approvals (in effect, as their agent). And they won't take the action to submit them to the Linux archives. As an OEM customer we are bound to follow their NDA requirements and approvals. Someone not bound by the NDA, on the other hand, can do so <hint hint>.

Conversion from their header format to binary is as follows:

	for i in aap1img.h ilaimg.h iopimg.h istrimg.h ; do
		gcc -x c -c -o ${i%.h}.bin ${i}
		objcopy -O binary ${i%h}.bin
	done

Sincerely -- Mark Salyzyn

On Apr 27, 2012, at 9:06 PM, Jack Wang wrote:

> Thanks Mark,
> 
> So how we get the bin images? PMCS only offer the converted c Header file
> for this, we need users who want to use this function convert the header
> file to bin file.
> 
> Patch need a little more time to look into, will comment back soon.
> 
> Jack
> 
> 
>> 
>> The pm8001 can be delivered as a standalone product with flash-programmed
>> firmware images, or without the flash present requiring the driver to
> upload
>> the images into the chip's RAM and then run. This is called HDA mode.
>> 
>> We add support for this firmware upload in the enclosed patch. We try some
>> basic initialization checks of the Firmware, and if it appears dead, we
> make
>> the assumption the adapter must in-fact be halted in this HDA mode. The
>> Firmware images themselves have not been cleared for open-release by PMC,
> but
>> they are available in OpenSolaris <hint hint>. PMC's rationalization for
> not
>> wanting an open-release of the Firmware Images is that they do not want to
>> take support calls except from paying OEMs (such as Xyratex) that are
> embedding
>> PMC product into the motherboards and thus may have a tested combination
> of
>> Firmware and Hardware. Please respect this sentiment. Images are expected
> in:
>> 
>> /lib/firmware/aap1img.bin
>> /lib/firmware/ilaimg.bin
>> /lib/firmware/iopimg.bin
>> /lib/firmware/istrimg.bin
>> 
>> using the exact same naming convention as PMC and in OpenSolaris (and its
>> followon children) for these image files.
>> 
>> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
>> 
>> drivers/scsi/pm8001/pm8001_hwi.c  |  584
>> +++++++++++++++++++++++++++++++++++---
>> drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>> drivers/scsi/pm8001/pm8001_init.c |   30 +
>> drivers/scsi/pm8001/pm8001_sas.h  |    3
>> 4 files changed, 613 insertions(+), 41 deletions(-)
>> 
>> Please see enclosed attachment
>> 
>> 
>> ______________________________________________________________________
>> This email may contain privileged or confidential information, which
> should
>> only be used for the purpose for which it was sent by Xyratex. No further
> rights
>> or licenses are granted to use such information. If you are not the
> intended
>> recipient of this message, please notify the sender by return and delete
> it.
>> You may not use, copy, disclose or rely on the information contained in
> it.
>> 
>> Internet email is susceptible to data corruption, interception and
>> unauthorised amendment for which Xyratex does not accept liability. While
> we
>> have taken reasonable precautions to ensure that this email is free of
> viruses,
>> Xyratex does not accept liability for the presence of any computer viruses
> in
>> this email, nor for any losses caused as a result of viruses.
>> 
>> Xyratex Technology Limited (03134912), Registered in England & Wales,
>> Registered Office, Langstone Road, Havant, Hampshire, PO9 1SA.
>> 
>> The Xyratex group of companies also includes, Xyratex Ltd, registered in
>> Bermuda, Xyratex International Inc, registered in California, Xyratex
>> (Malaysia) Sdn Bhd registered in Malaysia, Xyratex Technology (Wuxi) Co
> Ltd
>> registered in The People's Republic of China and Xyratex Japan Limited
>> registered in Japan.
>> ______________________________________________________________________
>> 
>> 
> 
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-30 13:49   ` Mark Salyzyn
@ 2012-04-30 16:56     ` Mark Salyzyn
  2012-05-01  1:10       ` jack_wang
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Salyzyn @ 2012-04-30 16:56 UTC (permalink / raw)
  To: Jack Wang
  Cc: Mark Salyzyn, linux-scsi, 'James Bottomley',
	'lindar_liu', '于爱华',
	'john_gong'

Upon further investigation of the documentation, bit [2] (0x04) is the Force HDA mode, but the flashless operations are bit [3] (0x08) meaning Firmware to be loaded in HDA mode. I expect either SEEPROM bit set is enough.

Xyratex is NOT setting the SEEPROM bits so the flags are 'incorrect' and a value of Zero, yet the hardware is in-fact in HDA-mode because of the lack of flash, so the mpi_uninit_check() still makes loads of sense to capture this state and engineer ourselves out of that problem.

Jack, would the following trailing fragment to replace the six lines of the one you noted below resolve your concern? :

+	return pm8001_ha->main_cfg_tbl.hda_mode_flag & 0xC;

If so, I will 'take2' the patch with this change as I have not seen any other reviews.

Thanks for the excellent catch.

Sincerely -- Mark Salyzyn

On Apr 30, 2012, at 9:49 AM, Mark Salyzyn wrote:

> You are right ... however this code is 'never reached' since mpi_uninit_check() generally fails before this in the chip_in_hda_mode set of tests.
> 
> I instrumented up, on our HDA mode chip, we are seeing a value of ZERO in MAIN_HDA_FLAGS_OFFSET ... Ahh, the world of initializing hardware that is in an indeterminate (code not running) state ...
> 
> -- Mark
> 
> On Apr 28, 2012, at 2:07 AM, Jack Wang wrote:
> 
>> 
>> +	data = pm8001_mr32(
>> +		pm8001_ha->main_cfg_tbl_addr,
>> +		pm8001_ha->main_cfg_tbl.hda_mode_flag);
>> +	PM8001_INIT_DBG(pm8001_ha,
>> +		pm8001_printk("*MAIN_HDA_FLAGS = 0x%x\n", data));
>> +	return data & 0x4;
>> 
>> Here seems wrong, you may want to check the force hda bit? So you need to
>> read offset #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
>> 
>> Jack
>> 
>> 
>>> 
>>> The pm8001 can be delivered as a standalone product with flash-programmed
>>> firmware images, or without the flash present requiring the driver to
>> upload
>>> the images into the chip's RAM and then run. This is called HDA mode.
>>> 
>>> We add support for this firmware upload in the enclosed patch. We try some
>>> basic initialization checks of the Firmware, and if it appears dead, we
>> make
>>> the assumption the adapter must in-fact be halted in this HDA mode. The
>>> Firmware images themselves have not been cleared for open-release by PMC,
>> but
>>> they are available in OpenSolaris <hint hint>. PMC's rationalization for
>> not
>>> wanting an open-release of the Firmware Images is that they do not want to
>>> take support calls except from paying OEMs (such as Xyratex) that are
>> embedding
>>> PMC product into the motherboards and thus may have a tested combination
>> of
>>> Firmware and Hardware. Please respect this sentiment. Images are expected
>> in:
>>> 
>>> /lib/firmware/aap1img.bin
>>> /lib/firmware/ilaimg.bin
>>> /lib/firmware/iopimg.bin
>>> /lib/firmware/istrimg.bin
>>> 
>>> using the exact same naming convention as PMC and in OpenSolaris (and its
>>> followon children) for these image files.
>>> 
>>> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
>>> 
>>> drivers/scsi/pm8001/pm8001_hwi.c  |  584
>>> +++++++++++++++++++++++++++++++++++---
>>> drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>>> drivers/scsi/pm8001/pm8001_init.c |   30 +
>>> drivers/scsi/pm8001/pm8001_sas.h  |    3
>>> 4 files changed, 613 insertions(+), 41 deletions(-)
>>> 
>>> Please see enclosed attachment
>> 
>> 
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Re: [PATCH] pm8001: support HDA (flashless) mode
  2012-04-30 16:56     ` Mark Salyzyn
@ 2012-05-01  1:10       ` jack_wang
  0 siblings, 0 replies; 12+ messages in thread
From: jack_wang @ 2012-05-01  1:10 UTC (permalink / raw)
  Cc: Mark Salyzyn, linux-scsi, James Bottomley, lindar_liu,
	crystal_yu, john_gong

Hi Mark,

Yes, I think this should be fine, you can add by reviewed-by at the take2.

Thanks and regards!



--------------
jack_wang
>Upon further investigation of the documentation, bit [2] (0x04) is the Force HDA mode, but the flashless operations are bit [3] (0x08) meaning Firmware to be loaded in HDA mode. I expect either SEEPROM bit set is enough.
>
>Xyratex is NOT setting the SEEPROM bits so the flags are 'incorrect' and a value of Zero, yet the hardware is in-fact in HDA-mode because of the lack of flash, so the mpi_uninit_check() still makes loads of sense to capture this state and engineer ourselves out of that problem.
>
>Jack, would the following trailing fragment to replace the six lines of the one you noted below resolve your concern? :
>
>+	return pm8001_ha->main_cfg_tbl.hda_mode_flag & 0xC;
>
>If so, I will 'take2' the patch with this change as I have not seen any other reviews.
>
>Thanks for the excellent catch.
>
>Sincerely -- Mark Salyzyn
>
>On Apr 30, 2012, at 9:49 AM, Mark Salyzyn wrote:
>
>> You are right ... however this code is 'never reached' since mpi_uninit_check() generally fails before this in the chip_in_hda_mode set of tests.
>> 
>> I instrumented up, on our HDA mode chip, we are seeing a value of ZERO in MAIN_HDA_FLAGS_OFFSET ... Ahh, the world of initializing hardware that is in an indeterminate (code not running) state ...
>> 
>> -- Mark
>> 
>> On Apr 28, 2012, at 2:07 AM, Jack Wang wrote:
>> 
>>> 
>>> +	data = pm8001_mr32(
>>> +		pm8001_ha->main_cfg_tbl_addr,
>>> +		pm8001_ha->main_cfg_tbl.hda_mode_flag);
>>> +	PM8001_INIT_DBG(pm8001_ha,
>>> +		pm8001_printk("*MAIN_HDA_FLAGS = 0x%x\n", data));
>>> +	return data & 0x4;
>>> 
>>> Here seems wrong, you may want to check the force hda bit? So you need to
>>> read offset #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
>>> 
>>> Jack
>>> 
>>> 
>>>> 
>>>> The pm8001 can be delivered as a standalone product with flash-programmed
>>>> firmware images, or without the flash present requiring the driver to
>>> upload
>>>> the images into the chip's RAM and then run. This is called HDA mode.
>>>> 
>>>> We add support for this firmware upload in the enclosed patch. We try some
>>>> basic initialization checks of the Firmware, and if it appears dead, we
>>> make
>>>> the assumption the adapter must in-fact be halted in this HDA mode. The
>>>> Firmware images themselves have not been cleared for open-release by PMC,
>>> but
>>>> they are available in OpenSolaris <hint hint>. PMC's rationalization for
>>> not
>>>> wanting an open-release of the Firmware Images is that they do not want to
>>>> take support calls except from paying OEMs (such as Xyratex) that are
>>> embedding
>>>> PMC product into the motherboards and thus may have a tested combination
>>> of
>>>> Firmware and Hardware. Please respect this sentiment. Images are expected
>>> in:
>>>> 
>>>> /lib/firmware/aap1img.bin
>>>> /lib/firmware/ilaimg.bin
>>>> /lib/firmware/iopimg.bin
>>>> /lib/firmware/istrimg.bin
>>>> 
>>>> using the exact same naming convention as PMC and in OpenSolaris (and its
>>>> followon children) for these image files.
>>>> 
>>>> Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
>>>> 
>>>> drivers/scsi/pm8001/pm8001_hwi.c  |  584
>>>> +++++++++++++++++++++++++++++++++++---
>>>> drivers/scsi/pm8001/pm8001_hwi.h  |   37 ++
>>>> drivers/scsi/pm8001/pm8001_init.c |   30 +
>>>> drivers/scsi/pm8001/pm8001_sas.h  |    3
>>>> 4 files changed, 613 insertions(+), 41 deletions(-)
>>>> 
>>>> Please see enclosed attachment
>>> 
>>> 
>> 
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>__________ Information from ESET NOD32 Antivirus, version of virus signature database 5659 (20101129) __________
>
>The message was checked by ESET NOD32 Antivirus.
>
>http://www.eset.com
>
>
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] pm8001: support HDA (flashless) mode (take 2)
  2012-04-27 17:10 [PATCH] pm8001: support HDA (flashless) mode Mark Salyzyn
                   ` (2 preceding siblings ...)
  2012-04-28  6:07 ` Jack Wang
@ 2012-05-01 12:45 ` Mark Salyzyn
  2012-05-03  0:35   ` RE " Jack Wang
  3 siblings, 1 reply; 12+ messages in thread
From: Mark Salyzyn @ 2012-05-01 12:45 UTC (permalink / raw)
  To: linux-scsi
  Cc: Mark Salyzyn, Jack Wang, James Bottomley, lindar_liu,
	于爱华,
	john_gong

[-- Attachment #1: Type: text/plain, Size: 1851 bytes --]

The pm8001 can be delivered as a standalone product with flash-programmed
firmware images, or without the flash present requiring the driver to upload
the images into the chip's RAM and then run. This is called flashless HDA mode.

We add support for this firmware upload in the enclosed patch. We try some
basic initialization checks of the Firmware, and if it appears dead, we make
the assumption the adapter must in-fact be halted in this HDA mode. The
Firmware images themselves have not been cleared for open-release by PMC, but
they are available in OpenSolaris <hint hint>. PMC's rationalization for not
wanting an open-release of the Firmware Images is that they do not want to
take support calls except from paying OEMs (such as Xyratex) that are embedding
PMC product into the motherboards and thus may have a tested combination of
Firmware and Hardware. Please respect this sentiment. Images are expected in:

/lib/firmware/aap1img.bin
/lib/firmware/ilaimg.bin
/lib/firmware/iopimg.bin
/lib/firmware/istrimg.bin

using the exact same naming convention as PMC and in OpenSolaris (and its
followon children) for these image files.

Take 2 of the patch, added manifests MAIN_HDA_FLAGS_FORCE_HDA and
MAIN_HDA_FLAGS_HDA_FW to check against the bit value of .hda_mode_flag
if the SEEPROM is forcing HDA flashless mode.

Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
Reviewed-by: Jack Wang <jack_wang@usish.com>
Cc: James Bottomley <JBottomley@parallels.com>
Cc: lindar_liu@usish.com
Cc: crystal_yu@usish.com
Cc: john_gong@usish.com

 drivers/scsi/pm8001/pm8001_hwi.c  |  575 +++++++++++++++++++++++++++++++++++---
 drivers/scsi/pm8001/pm8001_hwi.h  |   40 ++
 drivers/scsi/pm8001/pm8001_init.c |   30 +
 drivers/scsi/pm8001/pm8001_sas.h  |    3 
 4 files changed, 607 insertions(+), 41 deletions(-)

[-- Attachment #2: pm8001-hda-2.patch --]
[-- Type: application/octet-stream, Size: 25748 bytes --]

The pm8001 can be delivered as a standalone product with flash-programmed
firmware images, or without the flash present requiring the driver to upload
the images into the chip's RAM and then run. This is called flashless HDA mode.

We add support for this firmware upload in the enclosed patch. We try some
basic initialization checks of the Firmware, and if it appears dead, we make
the assumption the adapter must in-fact be halted in this HDA mode. The
Firmware images themselves have not been cleared for open-release by PMC, but
they are available in OpenSolaris <hint hint>. PMC's rationalization for not
wanting an open-release of the Firmware Images is that they do not want to
take support calls except from paying OEMs (such as Xyratex) that are embedding
PMC product into the motherboards and thus may have a tested combination of
Firmware and Hardware. Please respect this sentiment. Images are expected in:

/lib/firmware/aap1img.bin
/lib/firmware/ilaimg.bin
/lib/firmware/iopimg.bin
/lib/firmware/istrimg.bin

using the exact same naming convention as PMC and in OpenSolaris (and its
followon children) for these image files.

Take 2 of the patch, added manifests MAIN_HDA_FLAGS_FORCE_HDA and
MAIN_HDA_FLAGS_HDA_FW to check against the bit value of .hda_mode_flag
if the SEEPROM is forcing HDA flashless mode.

Signed-off-by: Mark Salyzyn <mark_salyzyn@xyratex.com>
Reviewed-by: Jack Wang <jack_wang@usish.com>
Cc: James Bottomley <JBottomley@parallels.com>
Cc: lindar_liu@usish.com
Cc: crystal_yu@usish.com
Cc: john_gong@usish.com

 drivers/scsi/pm8001/pm8001_hwi.c  |  575 +++++++++++++++++++++++++++++++++++---
 drivers/scsi/pm8001/pm8001_hwi.h  |   40 ++
 drivers/scsi/pm8001/pm8001_init.c |   30 +
 drivers/scsi/pm8001/pm8001_sas.h  |    3 
 4 files changed, 607 insertions(+), 41 deletions(-)

diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 8477df4..4ef7342 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -37,11 +37,13 @@
  * POSSIBILITY OF SUCH DAMAGES.
  *
  */
- #include <linux/slab.h>
- #include "pm8001_sas.h"
- #include "pm8001_hwi.h"
- #include "pm8001_chips.h"
- #include "pm8001_ctl.h"
+#include <linux/slab.h>
+#include "pm8001_sas.h"
+#include "pm8001_hwi.h"
+#include "pm8001_chips.h"
+#include "pm8001_ctl.h"
+
+#include <linux/firmware.h>
 
 /**
  * read_main_config_table - read the configure table and save it.
@@ -63,6 +65,9 @@ static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha)
 		pm8001_mr32(address, MAIN_OBQ_OFFSET);
 	pm8001_ha->main_cfg_tbl.hda_mode_flag	=
 		pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET);
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("MAIN_HDA_FLAGS = 0x%x\n",
+			pm8001_ha->main_cfg_tbl.hda_mode_flag));
 
 	/* read analog Setting offset from the configuration table */
 	pm8001_ha->main_cfg_tbl.anolog_setup_table_offset =
@@ -597,6 +602,475 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
 		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20);
 }
 
+static void pm8001_hda_send_cmd(struct pm8001_hba_info *pm8001_ha,
+				u32 arg_array[], u32 num_args, u32 cmd)
+{
+	u32	reg;
+	u32	i;
+
+	for (i = 0; i < num_args; i++)
+		pm8001_cw32(pm8001_ha, 3, HDA_CMD_OFFSET+(i*4), arg_array[i]);
+
+	reg = pm8001_cr32(pm8001_ha, 3, HDA_CMD_OFFSET+28);
+	reg = (reg & HDA_SEQ_ID_BITS) >> 16;
+	if (reg == 0xff)
+		reg = 0;
+	reg++;
+	reg = ((HDA_C_PA << 24) | (reg << 16) |  cmd);
+	pm8001_cw32(pm8001_ha, 3, HDA_CMD_OFFSET+28, reg);
+}
+
+static u32 pm8001_hda_recv_rsp(struct pm8001_hba_info *pm8001_ha, u32 cmd)
+{
+	u32	rsp;
+	u32	i = 0;
+
+	do {
+		mdelay(10);
+		rsp = pm8001_cr32(pm8001_ha, 3, HDA_CMD_OFFSET+28);
+		rsp = rsp & HDA_CODE_BITS;
+
+		switch (cmd) {
+		case HDAC_CMD_EXEC:
+			if (rsp == HDA_RSP_EXEC)
+				return 1;
+			if (rsp == HDA_RSP_BAD_IMG)
+				return 0;
+			if (rsp == HDA_RSP_BAD_CMD)
+				return 0;
+			break;
+		}
+		i++;
+	} while (i < 200);
+
+	return 1;
+}
+
+static u32 pm8001_bar4_cpy(struct pm8001_hba_info *pm8001_ha,
+	u32 base, u32 offset, const unsigned char array[], u32 alen)
+{
+	u32	dbase;
+	u32	doffset;
+	u32	*larray;
+	u32	val;
+	u32	csize;
+	u32	wc;
+	u32	i = 0;
+	unsigned long flags;
+
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("alen = 0x%x\n", alen));
+
+	dbase = (base+offset) & MB3_SHIFT_MASK;
+	doffset = offset & MB3_OFFSET_MASK;
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	do {
+		if (-1 == pm8001_bar4_shift(pm8001_ha, dbase)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			return 0;
+		}
+
+		if ((doffset+alen) > SIZE_64KB)
+			csize = SIZE_64KB - doffset;
+		else
+			csize = alen;
+
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR dbase = 0x%x\n", dbase));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR doffset = 0x%x\n", doffset));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR size = 0x%x\n", csize));
+
+		wc = ((csize % 4) > 0) ? ((csize / 4) + 1) : (csize / 4);
+		larray = (u32 *)array;
+		for (i = 0; i < wc; i++) {
+			val = larray[i];
+			pm8001_cw32(pm8001_ha, 2, (doffset + (i*4)), val);
+		}
+
+		alen -= csize;
+		dbase += SIZE_64KB;
+		doffset = 0;
+		array = array + csize;
+	} while (alen != 0);
+
+	if (-1 == pm8001_bar4_shift(pm8001_ha, 0x0)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+
+	return 1;
+}
+
+static u32 pm8001_bar4_cpy_big(struct pm8001_hba_info *pm8001_ha,
+	u32 base, u32 offset, const unsigned char array[], u32 alen)
+{
+	u32	dbase;
+	u32	doffset;
+	u32	*larray;
+	u32	val;
+	u32	csize;
+	u32	wc;
+	u32	i = 0;
+	u8 *local_buffer = NULL;
+	unsigned long flags;
+
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("alen = 0x%x\n", alen));
+
+	dbase = (base+offset) & MB3_SHIFT_MASK;
+	doffset = offset & MB3_OFFSET_MASK;
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	do {
+		if (-1 == pm8001_bar4_shift(pm8001_ha, dbase)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			return 0;
+		}
+
+		if ((doffset+alen) > SIZE_64KB)
+			csize = SIZE_64KB - doffset;
+		else
+			csize = alen;
+
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR dbase = 0x%x\n", dbase));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR doffset = 0x%x\n", doffset));
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("ILA STR size = 0x%x\n", csize));
+
+		wc = ((csize % 4) > 0) ? ((csize / 4) + 1) : (csize / 4);
+		local_buffer = kmalloc(csize, GFP_KERNEL);
+		if (local_buffer != NULL)
+			memcpy(local_buffer, array, csize);
+		larray = (u32 *)local_buffer;
+		for (i = 0; i < wc; i++) {
+			val = larray[i];
+			pm8001_cw32(pm8001_ha, 2, (doffset + (i*4)), val);
+		}
+		kfree(local_buffer);
+		alen -= csize;
+		dbase += SIZE_64KB;
+		doffset = 0;
+		array = array + csize;
+	} while (alen != 0);
+
+	if (-1 == pm8001_bar4_shift(pm8001_ha, 0x0)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+
+	return 1;
+}
+
+
+static int pm8001_ishdar_idle(struct pm8001_hba_info *pm8001_ha)
+{
+	u32     hdaw;
+	u32     pcilogic;
+
+	pcilogic = get_pci_bar_index(0x24);
+
+	hdaw = pm8001_cr32(pm8001_ha, pcilogic, HDA_RSP_OFFSET+28);
+	if ((((hdaw & HDA_PA_BITS) >> 24) == HDA_R_PA)
+	 && ((hdaw & HDA_CODE_BITS) == HDA_RSP_IDLE))
+		return 1;
+
+	return 0;
+}
+
+static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha);
+
+/* Catch-22, this is called before chip initialization, values may change */
+static int __devinit pm8001_chip_in_hda_mode(struct pm8001_hba_info *pm8001_ha)
+{
+	u32	data;
+
+	if (!pm8001_ha->main_cfg_tbl_addr)
+		init_pci_device_addresses(pm8001_ha);
+	if (!pm8001_ha->main_cfg_tbl_addr)
+		return 0;
+	if (mpi_uninit_check(pm8001_ha) != 0) {
+		/* Must be sick, must be in HDA mode? */
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("MPI state not ready, in HDA mode?\n"));
+		return 1;
+	}
+	/* check the firmware status */
+	if (-1 == check_fw_ready(pm8001_ha)) {
+		/* Must be sick, must be in HDA mode? */
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("Firmware is not ready, in HDA mode?\n"));
+		return 1;
+	}
+	/* SEEPROM configuration bits */
+	if (!pm8001_ha->main_cfg_tbl.hda_mode_flag)
+		read_main_config_table(pm8001_ha);
+	return pm8001_ha->main_cfg_tbl.hda_mode_flag
+	 & (MAIN_HDA_FLAGS_FORCE_HDA|MAIN_HDA_FLAGS_HDA_FW);
+}
+
+static int
+pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature);
+
+static int pm8001_chip_hda_mode(struct pm8001_hba_info *pm8001_ha)
+{
+	int	i = 0;
+	u32	arga[6];
+	u32	reg;
+	u32	aap1_offset;
+	u32	fw_offset;
+	u32	pad1;
+	u32	pad2;
+	u8 *istr_buffer = NULL;
+	u32 istr_length = 0;
+	u8 *ila_buffer = NULL;
+	u32 ila_length = 0;
+	u32 aap1_length = 0;
+	u32 iop_length = 0;
+	u8 firmware_released = true;
+
+	/*get initial string image*/
+	if (request_firmware(&pm8001_ha->fw_image, "istrimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get istrimg.bin\n");
+		goto err_out_hda;
+	}
+	istr_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get istrimg.bin, length is %x\n", istr_length);
+	istr_buffer = kmalloc(pm8001_ha->fw_image->size, GFP_KERNEL);
+	if (istr_buffer == NULL) {
+		release_firmware(pm8001_ha->fw_image);
+		goto err_out_hda;
+	}
+
+	memcpy(istr_buffer, pm8001_ha->fw_image->data,
+		pm8001_ha->fw_image->size);
+	release_firmware(pm8001_ha->fw_image);
+
+	/*Get ILA image*/
+	if (request_firmware(&pm8001_ha->fw_image, "ilaimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get ilaimg.bin\n");
+		goto err_out_hda;
+	}
+
+	ila_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get ilaimg.bin, length is %x\n", ila_length);
+	ila_buffer = kmalloc(pm8001_ha->fw_image->size, GFP_KERNEL);
+	if (ila_buffer == NULL) {
+		release_firmware(pm8001_ha->fw_image);
+		goto err_out_hda;
+	}
+
+	memcpy(ila_buffer, pm8001_ha->fw_image->data,
+		pm8001_ha->fw_image->size);
+	release_firmware(pm8001_ha->fw_image);
+
+	/*get aap1 image*/
+	if (request_firmware(&pm8001_ha->fw_image, "aap1img.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get aap1img.bin\n");
+		goto err_out_hda;
+	}
+	aap1_length = pm8001_ha->fw_image->size;
+	pm8001_printk("Get aap1img.bin, length is %x\n", aap1_length);
+
+	firmware_released = false;
+
+	/* Try soft reset until it goes into HDA mode */
+	pm8001_chip_soft_rst(pm8001_ha, SPC_HDASOFT_RESET_SIGNATURE);
+	mdelay(10);
+	if (!pm8001_ishdar_idle(pm8001_ha)) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("SPC_HDASOFT_RESET: failed!\n"));
+		goto err_out_hda;
+	}
+
+	/* HDA Mode - Clear ODMR and ODCR */
+	pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
+	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
+
+	/* Step 1: Poll HDA_RSP_IDLE - HDA mode */
+	i = 0;
+	do {
+		mdelay(10);
+		if (pm8001_ishdar_idle(pm8001_ha))
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("HDA Mode: Timeout!\n")); /* 2 sec */
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("HDA Mode!\n"));
+
+	/* Step 2: Push the init string to 0x0047E000 & data compare */
+	pm8001_printk("istrimage length is %x\n", istr_length);
+	if (!pm8001_bar4_cpy(pm8001_ha, GSM_HDA_ILA_STR_BASE,
+			GSM_ILA_STR_OFFSET, istr_buffer, istr_length))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("ILA Str cpy done!\n"));
+
+	/* Tell FW ISTR is ready */
+	reg = (ILA_HDA_ISTR_IMG_DONE << 24) | istr_length;
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+	/* Step 3: Write the HDA mode SoftReset signature */
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0,
+		SPC_HDASOFT_RESET_SIGNATURE);
+
+	/* Step 4: Push the ILA image to 0x00400000 */
+	arga[1] = ila_length;
+	if (!pm8001_bar4_cpy(pm8001_ha, GSM_HDA_ILA_BASE, GSM_HDA_ILA_OFFSET,
+			ila_buffer, ila_length))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("ILA  cpy done!\n"));
+
+	/* Step 5: Tell boot ROM to authenticate ILA and execute it */
+	arga[0] = 0;
+	pm8001_hda_send_cmd(pm8001_ha, arga, 2, HDAC_CMD_EXEC);
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("CMD EXEC sent!\n"));
+
+	/*
+	 * Step 6: Checking response status from boot ROM,
+	 *         HDAR_EXEC (good), HDAR_BAD_CMD and HDAR_BAD_IMG
+	 */
+	if (!pm8001_hda_recv_rsp(pm8001_ha, HDAC_CMD_EXEC))
+		goto err_out_hda;
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("CMD EXEC rsp ok!\n"));
+
+	/* Step 7: Poll ILAHDA_AAP1IMGGET/Offset in MSGU Scratchpad 0 */
+	/* Check MSGU Scratchpad 1 [1,0] == 00 */
+	i = 0;
+	do {
+		mdelay(10);
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+		aap1_offset = reg & ~SCRATCH_PAD0_STATE_MASK;
+		reg = reg >> 24;
+		if (reg == ILA_HDA_AAP1_IMG_GET)
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("APP1_IMG_GET Poll timeout !\n"));
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("scratch pad 1 = 0x%x\n", reg));
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("scratch pad 2 = 0x%x\n", reg));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("APP1 img get ok!\n"));
+
+	/* Step 8: Copy AAP1 image, update the Host Scratchpad 3 */
+	reg = (ILA_HDA_AAP1_IMG_DONE << 24) | aap1_length;
+	if (!pm8001_bar4_cpy_big(pm8001_ha, GSM_HDA_ILA_BASE, aap1_offset,
+			pm8001_ha->fw_image->data, aap1_length)) {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+		goto err_out_hda;
+	} else {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("APP1  cpy done!\n"));
+
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+
+	/*Get IOP image*/
+	if (request_firmware(&pm8001_ha->fw_image, "iopimg.bin",
+			pm8001_ha->dev) != 0) {
+		pm8001_printk("Can not get istrimg.bin\n");
+		goto err_out_hda;
+	} else {
+		iop_length = pm8001_ha->fw_image->size;
+		pm8001_printk("Get iopimg.bin, length is %x\n", iop_length);
+		firmware_released = false;
+	}
+
+	/* Step 9: Poll ILAHDA_IOPIMGGET/Offset in MSGU Scratchpad 0 */
+	i = 0;
+	do {
+		mdelay(10);
+		reg = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+		fw_offset = reg & ~SCRATCH_PAD0_STATE_MASK;
+		reg = reg >> 24;
+		if (reg == ILA_HDA_IOP_IMG_GET)
+			break;
+		i++;
+	} while (i < 200);
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("IOP_IMG_GET Poll timeout !\n"));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("IOP img get ok!\n"));
+
+	/* Step 10: Copy IOP image, update the Host Scratchpad 3 */
+	reg = (ILA_HDA_IOP_IMG_DONE << 24) | iop_length;
+	if (!pm8001_bar4_cpy_big(pm8001_ha, GSM_HDA_ILA_BASE, fw_offset,
+			pm8001_ha->fw_image->data, iop_length)) {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+		goto err_out_hda;
+	} else {
+		release_firmware(pm8001_ha->fw_image);
+		firmware_released = true;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("IOP  cpy done!\n"));
+
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3, reg);
+
+	/* Clear the signature */
+	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, 0);
+
+	/* step 11: wait for the FW and IOP to get ready - 1 sec timeout */
+	/* Wait for the SPC Configuration Table to be ready */
+	i = 0;
+	do {
+		mdelay(10);
+		pad1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+		if (pad1 & SCRATCH_PAD1_RDY) {
+			pad2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+			if (pad2 & SCRATCH_PAD2_RDY)
+				break;
+		}
+		i++;
+	} while (i < 200);
+
+	if (i == 200) {
+		PM8001_INIT_DBG(pm8001_ha,
+			pm8001_printk("PAD 1 & 2 not Rdy !\n"));
+
+		goto err_out_hda;
+	}
+	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("HDA Mode Complete!\n"));
+
+	kfree(istr_buffer);
+	kfree(ila_buffer);
+	if (firmware_released == false)
+		release_firmware(pm8001_ha->fw_image);
+
+	return 1;
+
+err_out_hda:
+	kfree(istr_buffer);
+	kfree(ila_buffer);
+	if (firmware_released == false)
+		release_firmware(pm8001_ha->fw_image);
+
+	return 0;
+}
+
 /**
  * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
  * @pm8001_ha: our hba card information
@@ -704,40 +1178,60 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("Firmware is ready for reset .\n"));
 	} else {
-		unsigned long flags;
-		/* Trigger NMI twice via RB6 */
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
-		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("Shift Bar4 to 0x%x failed\n",
-					RB6_ACCESS_REG));
-			return -1;
-		}
-		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
-			RB6_MAGIC_NUMBER_RST);
-		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST);
-		/* wait for 100 ms */
-		mdelay(100);
-		regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
-			SCRATCH_PAD2_FWRDY_RST;
-		if (regVal != SCRATCH_PAD2_FWRDY_RST) {
-			regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
-			regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("TIMEOUT:MSGU_SCRATCH_PAD1"
-				"=0x%x, MSGU_SCRATCH_PAD2=0x%x\n",
-				regVal1, regVal2));
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("SCRATCH_PAD0 value = 0x%x\n",
-				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)));
-			PM8001_FAIL_DBG(pm8001_ha,
-				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
-				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+		if (pm8001_ishdar_idle(pm8001_ha)) {
+			/*
+			 *	For customers wants to do soft reset even the
+			 * chip is already in HDA mode
+			 *
+			 * Do not need to trigger RB6 twice
+			 */
+			;
+		} else {
+			unsigned long flags;
+			/* Trigger NMI twice via RB6 */
+			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			if (-1 == pm8001_bar4_shift(pm8001_ha,
+					RB6_ACCESS_REG)) {
+				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("Shift Bar4 to 0x%x "
+						"failed\n",
+						RB6_ACCESS_REG));
+				return -1;
+			}
+			pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
+				RB6_MAGIC_NUMBER_RST);
+			pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
+				RB6_MAGIC_NUMBER_RST);
+			/* wait for 100 ms */
+			mdelay(100);
+			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
+				SCRATCH_PAD2_FWRDY_RST;
+			if (regVal != SCRATCH_PAD2_FWRDY_RST) {
+				regVal1 = pm8001_cr32(pm8001_ha, 0,
+					MSGU_SCRATCH_PAD_1);
+				regVal2 = pm8001_cr32(pm8001_ha, 0,
+					MSGU_SCRATCH_PAD_2);
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("TIMEOUT:"
+						"MSGU_SCRATCH_PAD1=0x%x, "
+						"MSGU_SCRATCH_PAD2=0x%x\n",
+						regVal1, regVal2));
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("SCRATCH_PAD0 "
+						"value = 0x%x\n",
+						pm8001_cr32(pm8001_ha, 0,
+							MSGU_SCRATCH_PAD_0)));
+				PM8001_FAIL_DBG(pm8001_ha,
+					pm8001_printk("SCRATCH_PAD3 "
+						"value = 0x%x\n",
+						pm8001_cr32(pm8001_ha, 0,
+							MSGU_SCRATCH_PAD_3)));
+				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				return -1;
+			}
 			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
-			return -1;
 		}
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	}
 	return 0;
 }
@@ -1009,7 +1503,10 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
 
 	/* step 14: delay 10 usec - Normal Mode */
-	udelay(10);
+	if (signature == SPC_SOFT_RESET_SIGNATURE)
+		udelay(10);
+	else
+		mdelay(200);
 	/* check Soft Reset Normal mode or Soft Reset HDA mode */
 	if (signature == SPC_SOFT_RESET_SIGNATURE) {
 		/* step 15 (Normal Mode): wait until scratch pad1 register
@@ -4683,6 +5180,8 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
 
 const struct pm8001_dispatch pm8001_8001_dispatch = {
 	.name			= "pmc8001",
+	.chip_in_hda_mode	= pm8001_chip_in_hda_mode,
+	.chip_hda_mode		= pm8001_chip_hda_mode,
 	.chip_init		= pm8001_chip_init,
 	.chip_soft_rst		= pm8001_chip_soft_rst,
 	.chip_rst		= pm8001_hw_chip_rst,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 1a4611e..8fd2f2e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -855,6 +855,16 @@ struct set_dev_state_resp {
 #define MSIX_INTERRUPT_DISABLE		0x1
 #define MSIX_INTERRUPT_ENABLE		0x0
 
+/* ILA codes in MSGU Scratchpad 0 */
+#define ILA_HDA_IOP_IMG_GET              0x10
+#define ILA_HDA_AAP1_IMG_GET             0x11
+#define ILA_HDA_AAP2_IMG_GET             0x12
+#define ILA_HDA_EXITGOOD                 0x1F
+#define ILA_HDA_IOP_IMG_DONE             0x80
+#define ILA_HDA_AAP1_IMG_DONE            0x81
+#define ILA_HDA_ISTR_IMG_DONE            0x83
+
+#define SCRATCH_PAD0_STATE_MASK		0xFF000000
 
 /* state definition for Scratch Pad1 register */
 #define SCRATCH_PAD1_POR		0x00  /* power on reset state */
@@ -918,6 +928,9 @@ struct set_dev_state_resp {
 #define MAIN_FATAL_ERROR_RDUMP1_OFFSET	0x7C/* DWORD 0x1F */
 #define MAIN_FATAL_ERROR_RDUMP1_LENGTH	0x80/* DWORD 0x20 */
 #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
+# define MAIN_HDA_FLAGS_BOOTSTRAP_MASK	0x00000003
+# define MAIN_HDA_FLAGS_FORCE_HDA	0x00000004
+# define MAIN_HDA_FLAGS_HDA_FW		0x00000008
 #define MAIN_ANALOG_SETUP_OFFSET	0x88/* DWORD 0x22 */
 
 /* Gereral Status Table offset - byte offset */
@@ -952,8 +965,10 @@ struct set_dev_state_resp {
 #define PCIE_ERROR_INTERRUPT_ENABLE	0x003048
 #define PCIE_ERROR_INTERRUPT		0x00304C
 /* signature definition for host scratch pad0 register */
-#define SPC_SOFT_RESET_SIGNATURE	0x252acbcd
 /* Signature for Soft Reset */
+#define SPC_SOFT_RESET_SIGNATURE	0x252acbcd
+/* Signature for HDA Soft Reset without PCIe resetting */
+#define SPC_HDASOFT_RESET_SIGNATURE	0xa5aa27d7
 
 /* SPC Reset register - BAR4(0x20), BAR2(win) (need dynamic mapping) */
 #define SPC_REG_RESET			0x000000/* reset register */
@@ -987,6 +1002,14 @@ struct set_dev_state_resp {
 #define MBIC_AAP1_ADDR_BASE		0x060000
 #define MBIC_IOP_ADDR_BASE		0x070000
 #define GSM_ADDR_BASE			0x0700000
+#define GSM_HDA_ILA_STR_BASE            0x470000
+#define GSM_ILA_STR_OFFSET              0xE000
+#define GSM_HDA_ILA_BASE                0x400000
+#define GSM_HDA_ILA_OFFSET              0x0
+#define SIZE_64KB                       0x00010000
+#define MB3_SHIFT_MASK                  0xFFFF0000
+#define MB3_OFFSET_MASK                 0x0000FFFF
+
 /* Dynamic map through Bar4 - 0x00700000 */
 #define GSM_CONFIG_RESET		0x00000000
 #define RAM_ECC_DB_ERR			0x00000018
@@ -998,10 +1021,23 @@ struct set_dev_state_resp {
 #define GSM_WRITE_DATA_PARITY_CHECK	0x00000048
 
 #define RB6_ACCESS_REG			0x6A0000
-#define HDAC_EXEC_CMD			0x0002
+#define HDA_CMD_OFFSET			0xfec0
+#define HDA_RSP_OFFSET			0xfee0
+#define HDAC_CMD_BUF_INFO		0x0001
+#define HDAC_CMD_EXEC			0x0002
+#define HDAC_CMD_RESET			0x0003
 #define HDA_C_PA			0xcb
+#define HDA_R_PA			0xdb
+#define HDA_PA_BITS			0xff000000
 #define HDA_SEQ_ID_BITS			0x00ff0000
+#define HDA_CODE_BITS			0x0000ffff
 #define HDA_GSM_OFFSET_BITS		0x00FFFFFF
+#define HDA_RSP_BUF_INFO		0x8001
+#define HDA_RSP_IDLE			0x8002
+#define HDA_RSP_BAD_IMG			0x8003
+#define HDA_RSP_BAD_CMD			0x8004
+#define HDA_RSP_INTL_ERR		0x8005
+#define HDA_RSP_EXEC			0x8006
 #define MBIC_AAP1_ADDR_BASE		0x060000
 #define MBIC_IOP_ADDR_BASE		0x070000
 #define GSM_ADDR_BASE			0x0700000
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 36efaa7..db5bd77 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_chips.h"
+#include "pm8001_hwi.h"
 
 static struct scsi_transport_template *pm8001_stt;
 
@@ -669,8 +670,35 @@ static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
 		rc = -ENOMEM;
 		goto err_out_free;
 	}
+	/*
+	 * Make sure we have at least a sane region 0
+	 *
+	 * We do this here because a failure in pm8001_pci_alloc
+	 * is just interpreted as a memory allocation failure.
+	 */
+	if (pm8001_ha->io_mem[0].memvirtaddr == NULL
+	 || pm8001_ha->io_mem[0].memsize < (1 << 15)) {
+		printk(KERN_ERR "BAR0 access bad: %p,%x\n",
+			pm8001_ha->io_mem[0].memvirtaddr,
+			pm8001_ha->io_mem[0].memsize);
+		rc = -ENXIO;
+		goto err_out_free;
+	}
 	list_add_tail(&pm8001_ha->list, &hba_list);
-	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+
+	/* HDA SEEPROM Force HDA Mode */
+	if (PM8001_CHIP_DISP->chip_in_hda_mode(pm8001_ha)) {
+		rc = PM8001_CHIP_DISP->chip_hda_mode(pm8001_ha);
+		if (!rc) {
+			rc = -EBUSY;
+			goto err_out_ha_free;
+		}
+		pm8001_ha->rst_signature = SPC_HDASOFT_RESET_SIGNATURE;
+	} else {
+		PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha,
+			SPC_SOFT_RESET_SIGNATURE);
+		pm8001_ha->rst_signature = SPC_SOFT_RESET_SIGNATURE;
+	}
 	rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
 	if (rc)
 		goto err_out_ha_free;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 1100820..4b7f2e0 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -130,6 +130,8 @@ struct pm8001_ioctl_payload {
 
 struct pm8001_dispatch {
 	char *name;
+	int (*chip_in_hda_mode)(struct pm8001_hba_info *pm8001_ha);
+	int (*chip_hda_mode)(struct pm8001_hba_info *pm8001_ha);
 	int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
 	int (*chip_soft_rst)(struct pm8001_hba_info *pm8001_ha, u32 signature);
 	void (*chip_rst)(struct pm8001_hba_info *pm8001_ha);
@@ -384,6 +386,7 @@ struct pm8001_hba_info {
 	u32			logging_level;
 	u32			fw_status;
 	const struct firmware 	*fw_image;
+	u32			rst_signature;
 };
 
 struct pm8001_work {

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE [PATCH] pm8001: support HDA (flashless) mode (take 2)
  2012-05-01 12:45 ` [PATCH] pm8001: support HDA (flashless) mode (take 2) Mark Salyzyn
@ 2012-05-03  0:35   ` Jack Wang
  2012-05-03 17:18     ` Mark Salyzyn
  0 siblings, 1 reply; 12+ messages in thread
From: Jack Wang @ 2012-05-03  0:35 UTC (permalink / raw)
  To: linux-scsi
  Cc: 'James Bottomley', 'lindar_liu',
	'于爱华', 'john_gong'

Hi Mark,

I found other issue in this patch need to be addressed. when HDA mode is
enable, we need also change the soft reset signature to HDA signature in
pci_remove/suspend/resume function.

and in pm8001_chip_init, check fw ready is not need for HDA mode.


Best regards

Jack



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RE [PATCH] pm8001: support HDA (flashless) mode (take 2)
  2012-05-03  0:35   ` RE " Jack Wang
@ 2012-05-03 17:18     ` Mark Salyzyn
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Salyzyn @ 2012-05-03 17:18 UTC (permalink / raw)
  To: Jack Wang
  Cc: Mark Salyzyn, linux-scsi, 'James Bottomley',
	'lindar_liu', '于爱华',
	'john_gong'

I had viewed the hot-plug changes as separate (I see now that was a bogus distinction), I will merge them in.

Yes, the check_fw_ready is not needed, but was left in as an attempt to not touch the 'good path' for the other modes, I saw it as it could not hurt. I will test without it, and ensure operation in both our upstream code (?) and the kernel.org patch to be 100% sure. I was admittedly paranoid about removing that one. I had been experimenting and thinking about this one ever since Take-2 left the gate and am not yet satisfied.

I appreciate the comments, a sign of a deep dive into this one! Thanks!

Take-3 will arrive after testing, I will send you a PM preview to confirm ...

Sincerely -- Mark Salyzyn

On May 2, 2012, at 8:35 PM, Jack Wang wrote:

> Hi Mark,
> 
> I found other issue in this patch need to be addressed. when HDA mode is
> enable, we need also change the soft reset signature to HDA signature in
> pci_remove/suspend/resume function.
> 
> and in pm8001_chip_init, check fw ready is not need for HDA mode.
> 
> 
> Best regards
> 
> Jack
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-05-03 17:18 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-27 17:10 [PATCH] pm8001: support HDA (flashless) mode Mark Salyzyn
2012-04-28  1:06 ` Jack Wang
2012-04-30 14:00   ` Mark Salyzyn
2012-04-28  4:44 ` Re " Jack Wang
2012-04-30 13:43   ` Mark Salyzyn
2012-04-28  6:07 ` Jack Wang
2012-04-30 13:49   ` Mark Salyzyn
2012-04-30 16:56     ` Mark Salyzyn
2012-05-01  1:10       ` jack_wang
2012-05-01 12:45 ` [PATCH] pm8001: support HDA (flashless) mode (take 2) Mark Salyzyn
2012-05-03  0:35   ` RE " Jack Wang
2012-05-03 17:18     ` Mark Salyzyn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.