[SCSI] isci: initial sgpio write support

Basic support to initialize the gpio unit, accept an incomming
SAS_GPIO_REG_TX_GP bitstream, and translate it to the ODx.n fields in
the hardware registers.  If register indexes outside the supported range
are specified in the SMP frame we simply accept the write and return how
many registers (SFF-8485) were written (libsas reports this as residue
in the request).

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Dan Williams 2011-09-01 21:18:31 -07:00 коммит произвёл James Bottomley
Родитель 13257cfbc5
Коммит ad4f4c1de8
3 изменённых файлов: 87 добавлений и 0 удалений

Просмотреть файл

@ -1263,6 +1263,10 @@ void isci_host_deinit(struct isci_host *ihost)
{
int i;
/* disable output data selects */
for (i = 0; i < isci_gpio_count(ihost); i++)
writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
isci_host_change_state(ihost, isci_stopping);
for (i = 0; i < SCI_MAX_PORTS; i++) {
struct isci_port *iport = &ihost->ports[i];
@ -1281,6 +1285,12 @@ void isci_host_deinit(struct isci_host *ihost)
spin_unlock_irq(&ihost->scic_lock);
wait_for_stop(ihost);
/* disable sgpio: where the above wait should give time for the
* enclosure to sample the gpios going inactive
*/
writel(0, &ihost->scu_registers->peg0.sgpio.interface_control);
sci_controller_reset(ihost);
/* Cancel any/all outstanding port timers */
@ -2365,6 +2375,12 @@ int isci_host_init(struct isci_host *ihost)
for (i = 0; i < SCI_MAX_PHYS; i++)
isci_phy_init(&ihost->phys[i], ihost, i);
/* enable sgpio */
writel(1, &ihost->scu_registers->peg0.sgpio.interface_control);
for (i = 0; i < isci_gpio_count(ihost); i++)
writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code);
for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
struct isci_remote_device *idev = &ihost->devices[i];
@ -2760,3 +2776,56 @@ enum sci_task_status sci_controller_start_task(struct isci_host *ihost,
return status;
}
static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_count, u8 *write_data)
{
int d;
/* no support for TX_GP_CFG */
if (reg_index == 0)
return -EINVAL;
for (d = 0; d < isci_gpio_count(ihost); d++) {
u32 val = 0x444; /* all ODx.n clear */
int i;
for (i = 0; i < 3; i++) {
int bit = (i << 2) + 2;
bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i),
write_data, reg_index,
reg_count);
if (bit < 0)
break;
/* if od is set, clear the 'invert' bit */
val &= ~(bit << ((i << 2) + 2));
}
if (i < 3)
break;
writel(val, &ihost->scu_registers->peg0.sgpio.output_data_select[d]);
}
/* unless reg_index is > 1, we should always be able to write at
* least one register
*/
return d > 0;
}
int isci_gpio_write(struct sas_ha_struct *sas_ha, u8 reg_type, u8 reg_index,
u8 reg_count, u8 *write_data)
{
struct isci_host *ihost = sas_ha->lldd_ha;
int written;
switch (reg_type) {
case SAS_GPIO_REG_TX_GP:
written = sci_write_gpio_tx_gp(ihost, reg_index, reg_count, write_data);
break;
default:
written = -EINVAL;
}
return written;
}

Просмотреть файл

@ -440,6 +440,18 @@ static inline bool is_c0(struct pci_dev *pdev)
return false;
}
/* 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
* FSENG output
*/
#define SGPIO_HW_CONTROL 0x00000443
static inline int isci_gpio_count(struct isci_host *ihost)
{
return ARRAY_SIZE(ihost->scu_registers->peg0.sgpio.output_data_select);
}
void sci_controller_post_request(struct isci_host *ihost,
u32 request);
void sci_controller_release_frame(struct isci_host *ihost,
@ -542,4 +554,7 @@ void sci_port_configuration_agent_construct(
enum sci_status sci_port_configuration_agent_initialize(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent);
int isci_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
u8 reg_count, u8 *write_data);
#endif

Просмотреть файл

@ -192,6 +192,9 @@ static struct sas_domain_function_template isci_transport_ops = {
/* Phy management */
.lldd_control_phy = isci_phy_control,
/* GPIO support */
.lldd_write_gpio = isci_gpio_write,
};