Commit 9fee607f authored by Jeff Skirvin's avatar Jeff Skirvin Committed by James Bottomley
Browse files

[SCSI] isci: oem parameter format v1.3 (cable select)



v1.3 allows the attenuation of the attached cables to be specified to
the driver in terms of 'short', 'medium', and 'long' (see probe_roms.h).
These settings (per phy) are retrieved from the platform oem-parameters
(BIOS rom) or via a module parameter override.

Reviewed-by: default avatarJiangbi Liu <jiangbi.liu@intel.com>
Signed-off-by: default avatarJeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 594e566a
Loading
Loading
Loading
Loading
+40 −3
Original line number Diff line number Diff line
@@ -1666,6 +1666,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost
	/* Default to no SSC operation. */
	ihost->oem_parameters.controller.do_enable_ssc = false;

	/* Default to short cables on all phys. */
	ihost->oem_parameters.controller.cable_selection_mask = 0;

	/* Initialize all of the port parameter information to narrow ports. */
	for (index = 0; index < SCI_MAX_PORTS; index++) {
		ihost->oem_parameters.ports[index].phy_mask = 0;
@@ -1953,12 +1956,46 @@ void sci_controller_power_control_queue_remove(struct isci_host *ihost,

static int is_long_cable(int phy, unsigned char selection_byte)
{
	return 0;
	return !!(selection_byte & (1 << phy));
}

static int is_medium_cable(int phy, unsigned char selection_byte)
{
	return 0;
	return !!(selection_byte & (1 << (phy + 4)));
}

static enum cable_selections decode_selection_byte(
	int phy,
	unsigned char selection_byte)
{
	return ((selection_byte & (1 << phy)) ? 1 : 0)
		+ (selection_byte & (1 << (phy + 4)) ? 2 : 0);
}

static unsigned char *to_cable_select(struct isci_host *ihost)
{
	if (is_cable_select_overridden())
		return ((unsigned char *)&cable_selection_override)
			+ ihost->id;
	else
		return &ihost->oem_parameters.controller.cable_selection_mask;
}

enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy)
{
	return decode_selection_byte(phy, *to_cable_select(ihost));
}

char *lookup_cable_names(enum cable_selections selection)
{
	static char *cable_names[] = {
		[short_cable]     = "short",
		[long_cable]      = "long",
		[medium_cable]    = "medium",
		[undefined_cable] = "<undefined, assumed long>" /* bit 0==1 */
	};
	return (selection <= undefined_cable) ? cable_names[selection]
					      : cable_names[undefined_cable];
}

#define AFE_REGISTER_WRITE_DELAY 10
@@ -1967,10 +2004,10 @@ static void sci_controller_afe_initialization(struct isci_host *ihost)
{
	struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe;
	const struct sci_oem_params *oem = &ihost->oem_parameters;
	unsigned char cable_selection_mask = 0;
	struct pci_dev *pdev = ihost->pdev;
	u32 afe_status;
	u32 phy_id;
	unsigned char cable_selection_mask = *to_cable_select(ihost);

	/* Clear DFX Status registers */
	writel(0x0081000f, &afe->afe_dfx_master_control0);
+18 −0
Original line number Diff line number Diff line
@@ -447,6 +447,24 @@ static inline bool is_c1(struct pci_dev *pdev)
	return false;
}

enum cable_selections {
	short_cable     = 0,
	long_cable      = 1,
	medium_cable    = 2,
	undefined_cable = 3
};

#define CABLE_OVERRIDE_DISABLED (0x10000)

static inline int is_cable_select_overridden(void)
{
	return cable_selection_override < CABLE_OVERRIDE_DISABLED;
}

enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy);
void validate_cable_selections(struct isci_host *ihost);
char *lookup_cable_names(enum cable_selections);

/* set hw control for 'activity', even though active enclosures seem to drive
 * the activity led on their own.  Skip setting FSENG control on 'status' due
 * to unexpected operation and 'error' due to not being a supported automatic
+16 −0
Original line number Diff line number Diff line
@@ -122,6 +122,14 @@ unsigned char max_concurr_spinup;
module_param(max_concurr_spinup, byte, 0);
MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");

uint cable_selection_override = CABLE_OVERRIDE_DISABLED;
module_param(cable_selection_override, uint, 0);

MODULE_PARM_DESC(cable_selection_override,
		 "This field indicates length of the SAS/SATA cable between "
		 "host and device. If any bits > 15 are set (default) "
		 "indicates \"use platform defaults\"");

static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
@@ -412,6 +420,14 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
		return NULL;
	isci_host->shost = shost;

	dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
		 "{%s, %s, %s, %s}\n",
		 (is_cable_select_overridden() ? "* " : ""), isci_host->id,
		 lookup_cable_names(decode_cable_selection(isci_host, 3)),
		 lookup_cable_names(decode_cable_selection(isci_host, 2)),
		 lookup_cable_names(decode_cable_selection(isci_host, 1)),
		 lookup_cable_names(decode_cable_selection(isci_host, 0)));

	err = isci_host_init(isci_host);
	if (err)
		goto err_shost;
+1 −0
Original line number Diff line number Diff line
@@ -480,6 +480,7 @@ extern u16 ssp_inactive_to;
extern u16 stp_inactive_to;
extern unsigned char phy_gen;
extern unsigned char max_concurr_spinup;
extern uint cable_selection_override;

irqreturn_t isci_msix_isr(int vec, void *data);
irqreturn_t isci_intx_isr(int vec, void *data);
+36 −2
Original line number Diff line number Diff line
@@ -193,7 +193,8 @@ struct isci_oem_hdr {

#define ISCI_ROM_VER_1_0	0x10
#define ISCI_ROM_VER_1_1	0x11
#define ISCI_ROM_VER_LATEST	ISCI_ROM_VER_1_1
#define ISCI_ROM_VER_1_3	0x13
#define ISCI_ROM_VER_LATEST	ISCI_ROM_VER_1_3

/* Allowed PORT configuration modes APC Automatic PORT configuration mode is
 * defined by the OEM configuration parameters providing no PHY_MASK parameters
@@ -270,7 +271,40 @@ struct sci_oem_params {
			};
			uint8_t do_enable_ssc;
		};
		uint8_t reserved;
		/*
		 * This field indicates length of the SAS/SATA cable between
		 * host and device.
		 * This field is used make relationship between analog
		 * parameters of the phy in the silicon and length of the cable.
		 * Supported cable attenuation levels:
		 * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than
		 * 6m.
		 *
		 * This is bit mask field:
		 *
		 * BIT:      (MSB) 7     6     5     4
		 * ASSIGNMENT:   <phy3><phy2><phy1><phy0>  - Medium cable
		 *                                           length assignment
		 * BIT:            3     2     1     0  (LSB)
		 * ASSIGNMENT:   <phy3><phy2><phy1><phy0>  - Long cable length
		 *                                           assignment
		 *
		 * BITS 7-4 are set when the cable length is assigned to medium
		 * BITS 3-0 are set when the cable length is assigned to long
		 *
		 * The BIT positions are clear when the cable length is
		 * assigned to short.
		 *
		 * Setting the bits for both long and medium cable length is
		 * undefined.
		 *
		 * A value of 0x84 would assign
		 *    phy3 - medium
		 *    phy2 - long
		 *    phy1 - short
		 *    phy0 - short
		 */
		uint8_t cable_selection_mask;
	} controller;

	struct {