Skip to content

Commit

Permalink
[SCSI] ipr: add support for multiple stages of initialization
Browse files Browse the repository at this point in the history
This patch adds support for using the new IOA initialization feedback register.
It also enables 64 bit support in the ipr_ioafp_identify_hrrq and
ipr_mask_and_clear_interrupts routines.

Signed-off-by: Wayne Boyer <wayneb@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Wayne Boyer authored and James Bottomley committed Mar 3, 2010
1 parent f72919e commit 214777b
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 30 deletions.
185 changes: 155 additions & 30 deletions drivers/scsi/ipr.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,20 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
{
.set_interrupt_mask_reg = 0x0022C,
.clr_interrupt_mask_reg = 0x00230,
.clr_interrupt_mask_reg32 = 0x00230,
.sense_interrupt_mask_reg = 0x0022C,
.sense_interrupt_mask_reg32 = 0x0022C,
.clr_interrupt_reg = 0x00228,
.clr_interrupt_reg32 = 0x00228,
.sense_interrupt_reg = 0x00224,
.sense_interrupt_reg32 = 0x00224,
.ioarrin_reg = 0x00404,
.sense_uproc_interrupt_reg = 0x00214,
.sense_uproc_interrupt_reg32 = 0x00214,
.set_uproc_interrupt_reg = 0x00214,
.clr_uproc_interrupt_reg = 0x00218
.set_uproc_interrupt_reg32 = 0x00214,
.clr_uproc_interrupt_reg = 0x00218,
.clr_uproc_interrupt_reg32 = 0x00218
}
},
{ /* Snipe and Scamp */
Expand All @@ -121,13 +128,20 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
{
.set_interrupt_mask_reg = 0x00288,
.clr_interrupt_mask_reg = 0x0028C,
.clr_interrupt_mask_reg32 = 0x0028C,
.sense_interrupt_mask_reg = 0x00288,
.sense_interrupt_mask_reg32 = 0x00288,
.clr_interrupt_reg = 0x00284,
.clr_interrupt_reg32 = 0x00284,
.sense_interrupt_reg = 0x00280,
.sense_interrupt_reg32 = 0x00280,
.ioarrin_reg = 0x00504,
.sense_uproc_interrupt_reg = 0x00290,
.sense_uproc_interrupt_reg32 = 0x00290,
.set_uproc_interrupt_reg = 0x00290,
.clr_uproc_interrupt_reg = 0x00294
.set_uproc_interrupt_reg32 = 0x00290,
.clr_uproc_interrupt_reg = 0x00294,
.clr_uproc_interrupt_reg32 = 0x00294
}
},
{ /* CRoC */
Expand All @@ -136,13 +150,21 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
{
.set_interrupt_mask_reg = 0x00010,
.clr_interrupt_mask_reg = 0x00018,
.clr_interrupt_mask_reg32 = 0x0001C,
.sense_interrupt_mask_reg = 0x00010,
.sense_interrupt_mask_reg32 = 0x00014,
.clr_interrupt_reg = 0x00008,
.clr_interrupt_reg32 = 0x0000C,
.sense_interrupt_reg = 0x00000,
.sense_interrupt_reg32 = 0x00004,
.ioarrin_reg = 0x00070,
.sense_uproc_interrupt_reg = 0x00020,
.sense_uproc_interrupt_reg32 = 0x00024,
.set_uproc_interrupt_reg = 0x00020,
.set_uproc_interrupt_reg32 = 0x00024,
.clr_uproc_interrupt_reg = 0x00028,
.clr_uproc_interrupt_reg32 = 0x0002C,
.init_feedback_reg = 0x0005C,
.dump_addr_reg = 0x00064,
.dump_data_reg = 0x00068
}
Expand Down Expand Up @@ -592,10 +614,15 @@ static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,
ioa_cfg->allow_interrupts = 0;

/* Set interrupt mask to stop all new interrupts */
writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);
if (ioa_cfg->sis64)
writeq(~0, ioa_cfg->regs.set_interrupt_mask_reg);
else
writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);

/* Clear any pending interrupts */
writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg);
if (ioa_cfg->sis64)
writel(~0, ioa_cfg->regs.clr_interrupt_reg);
writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
}

Expand Down Expand Up @@ -2561,7 +2588,7 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,

/* Write IOA interrupt reg starting LDUMP state */
writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT),
ioa_cfg->regs.set_uproc_interrupt_reg);
ioa_cfg->regs.set_uproc_interrupt_reg32);

/* Wait for IO debug acknowledge */
if (ipr_wait_iodbg_ack(ioa_cfg,
Expand All @@ -2580,7 +2607,7 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,

/* Signal address valid - clear IOA Reset alert */
writel(IPR_UPROCI_RESET_ALERT,
ioa_cfg->regs.clr_uproc_interrupt_reg);
ioa_cfg->regs.clr_uproc_interrupt_reg32);

for (i = 0; i < length_in_words; i++) {
/* Wait for IO debug acknowledge */
Expand All @@ -2605,10 +2632,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,

/* Signal end of block transfer. Set reset alert then clear IO debug ack */
writel(IPR_UPROCI_RESET_ALERT,
ioa_cfg->regs.set_uproc_interrupt_reg);
ioa_cfg->regs.set_uproc_interrupt_reg32);

writel(IPR_UPROCI_IO_DEBUG_ALERT,
ioa_cfg->regs.clr_uproc_interrupt_reg);
ioa_cfg->regs.clr_uproc_interrupt_reg32);

/* Signal dump data received - Clear IO debug Ack */
writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,
Expand All @@ -2617,7 +2644,7 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
/* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */
while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) {
temp_pcii_reg =
readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
readl(ioa_cfg->regs.sense_uproc_interrupt_reg32);

if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT))
return 0;
Expand Down Expand Up @@ -4831,11 +4858,29 @@ static irqreturn_t ipr_isr(int irq, void *devp)
return IRQ_NONE;
}

int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;

/* If an interrupt on the adapter did not occur, ignore it */
/* If an interrupt on the adapter did not occur, ignore it.
* Or in the case of SIS 64, check for a stage change interrupt.
*/
if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
if (ioa_cfg->sis64) {
int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {

/* clear stage change */
writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
list_del(&ioa_cfg->reset_cmd->queue);
del_timer(&ioa_cfg->reset_cmd->timer);
ipr_reset_ioa_job(ioa_cfg->reset_cmd);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return IRQ_HANDLED;
}
}

spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return IRQ_NONE;
}
Expand Down Expand Up @@ -4878,8 +4923,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
if (ipr_cmd != NULL) {
/* Clear the PCI interrupt */
do {
writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
} while (int_reg & IPR_PCII_HRRQ_UPDATED &&
num_hrrq++ < IPR_MAX_HRRQ_RETRIES);

Expand Down Expand Up @@ -6887,7 +6932,7 @@ static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd)
}

/**
* ipr_ioafp_indentify_hrrq - Send Identify Host RRQ.
* ipr_ioafp_identify_hrrq - Send Identify Host RRQ.
* @ipr_cmd: ipr command struct
*
* This function send an Identify Host Request Response Queue
Expand All @@ -6896,7 +6941,7 @@ static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd)
* Return value:
* IPR_RC_JOB_RETURN
**/
static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd)
static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
Expand All @@ -6908,19 +6953,32 @@ static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd)
ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);

ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
if (ioa_cfg->sis64)
ioarcb->cmd_pkt.cdb[1] = 0x1;
ioarcb->cmd_pkt.cdb[2] =
((u32) ioa_cfg->host_rrq_dma >> 24) & 0xff;
((u64) ioa_cfg->host_rrq_dma >> 24) & 0xff;
ioarcb->cmd_pkt.cdb[3] =
((u32) ioa_cfg->host_rrq_dma >> 16) & 0xff;
((u64) ioa_cfg->host_rrq_dma >> 16) & 0xff;
ioarcb->cmd_pkt.cdb[4] =
((u32) ioa_cfg->host_rrq_dma >> 8) & 0xff;
((u64) ioa_cfg->host_rrq_dma >> 8) & 0xff;
ioarcb->cmd_pkt.cdb[5] =
((u32) ioa_cfg->host_rrq_dma) & 0xff;
((u64) ioa_cfg->host_rrq_dma) & 0xff;
ioarcb->cmd_pkt.cdb[7] =
((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff;
ioarcb->cmd_pkt.cdb[8] =
(sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff;

if (ioa_cfg->sis64) {
ioarcb->cmd_pkt.cdb[10] =
((u64) ioa_cfg->host_rrq_dma >> 56) & 0xff;
ioarcb->cmd_pkt.cdb[11] =
((u64) ioa_cfg->host_rrq_dma >> 48) & 0xff;
ioarcb->cmd_pkt.cdb[12] =
((u64) ioa_cfg->host_rrq_dma >> 40) & 0xff;
ioarcb->cmd_pkt.cdb[13] =
((u64) ioa_cfg->host_rrq_dma >> 32) & 0xff;
}

ipr_cmd->job_step = ipr_ioafp_std_inquiry;

ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
Expand Down Expand Up @@ -7004,6 +7062,57 @@ static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg)
memset(ioa_cfg->u.cfg_table, 0, ioa_cfg->cfg_table_size);
}

/**
* ipr_reset_next_stage - Process IPL stage change based on feedback register.
* @ipr_cmd: ipr command struct
*
* Return value:
* IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
**/
static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd)
{
unsigned long stage, stage_time;
u32 feedback;
volatile u32 int_reg;
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
u64 maskval = 0;

feedback = readl(ioa_cfg->regs.init_feedback_reg);
stage = feedback & IPR_IPL_INIT_STAGE_MASK;
stage_time = feedback & IPR_IPL_INIT_STAGE_TIME_MASK;

ipr_dbg("IPL stage = 0x%lx, IPL stage time = %ld\n", stage, stage_time);

/* sanity check the stage_time value */
if (stage_time < IPR_IPL_INIT_MIN_STAGE_TIME)
stage_time = IPR_IPL_INIT_MIN_STAGE_TIME;
else if (stage_time > IPR_LONG_OPERATIONAL_TIMEOUT)
stage_time = IPR_LONG_OPERATIONAL_TIMEOUT;

if (stage == IPR_IPL_INIT_STAGE_UNKNOWN) {
writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.set_interrupt_mask_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
stage_time = ioa_cfg->transop_timeout;
ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
} else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) {
ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
maskval = IPR_PCII_IPL_STAGE_CHANGE;
maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
return IPR_RC_JOB_CONTINUE;
}

ipr_cmd->timer.data = (unsigned long) ipr_cmd;
ipr_cmd->timer.expires = jiffies + stage_time * HZ;
ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
ipr_cmd->done = ipr_reset_ioa_job;
add_timer(&ipr_cmd->timer);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);

return IPR_RC_JOB_RETURN;
}

/**
* ipr_reset_enable_ioa - Enable the IOA following a reset.
* @ipr_cmd: ipr command struct
Expand All @@ -7020,27 +7129,35 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
volatile u32 int_reg;

ENTER;
ipr_cmd->job_step = ipr_ioafp_indentify_hrrq;
ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
ipr_init_ioa_mem(ioa_cfg);

ioa_cfg->allow_interrupts = 1;
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);

if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED),
ioa_cfg->regs.clr_interrupt_mask_reg);
ioa_cfg->regs.clr_interrupt_mask_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
return IPR_RC_JOB_CONTINUE;
}

/* Enable destructive diagnostics on IOA */
writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg);
writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg32);

writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg32);
if (ioa_cfg->sis64)
writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_mask_reg);

writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);

dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");

if (ioa_cfg->sis64) {
ipr_cmd->job_step = ipr_reset_next_stage;
return IPR_RC_JOB_CONTINUE;
}

ipr_cmd->timer.data = (unsigned long) ipr_cmd;
ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
Expand Down Expand Up @@ -7374,7 +7491,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)

if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) {
ipr_mask_and_clear_interrupts(ioa_cfg, ~0);
writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32);
ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
} else {
ipr_cmd->job_step = ioa_cfg->reset;
Expand Down Expand Up @@ -8104,15 +8221,23 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,

t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
t->clr_interrupt_reg = base + p->clr_interrupt_reg;
t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
t->sense_interrupt_reg = base + p->sense_interrupt_reg;
t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
t->ioarrin_reg = base + p->ioarrin_reg;
t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;

if (ioa_cfg->sis64) {
t->init_feedback_reg = base + p->init_feedback_reg;
t->dump_addr_reg = base + p->dump_addr_reg;
t->dump_data_reg = base + p->dump_data_reg;
}
Expand Down Expand Up @@ -8187,7 +8312,7 @@ static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
init_waitqueue_head(&ioa_cfg->msi_wait_q);
ioa_cfg->msi_received = 0;
ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg);
writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);

Expand All @@ -8198,7 +8323,7 @@ static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
} else if (ipr_debug)
dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq);

writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg);
writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ);
ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
Expand Down Expand Up @@ -8378,9 +8503,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
* If HRRQ updated interrupt is not masked, or reset alert is set,
* the card is in an unknown state and needs a hard reset
*/
mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
interrupts = readl(ioa_cfg->regs.sense_interrupt_reg32);
uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg32);
if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
ioa_cfg->needs_hard_reset = 1;
if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
Expand Down
Loading

0 comments on commit 214777b

Please sign in to comment.