Skip to content

Commit

Permalink
[SCSI] isci: oem parameter format v1.3 (cable select)
Browse files Browse the repository at this point in the history
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: Jiangbi Liu <jiangbi.liu@intel.com>
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
  • Loading branch information
Jeff Skirvin authored and James Bottomley committed Jan 16, 2012
1 parent 594e566 commit 9fee607
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 5 deletions.
43 changes: 40 additions & 3 deletions drivers/scsi/isci/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
18 changes: 18 additions & 0 deletions drivers/scsi/isci/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions drivers/scsi/isci/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/isci/isci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
38 changes: 36 additions & 2 deletions drivers/scsi/isci/probe_roms.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 9fee607

Please sign in to comment.