Skip to content

Commit

Permalink
[SCSI] lpfc 8.1.4 : Introduce lpfc_reset_barrier() function for reset…
Browse files Browse the repository at this point in the history
…s on dual channel adapters

Introduce lpfc_reset_barrier() function for resets on dual channel adapters

Workaround for a hardware errata on dual channel asics. There is a
potential for the chip to lock up on a reset if a shared dma engine is in
use. The (ugly) work around requires a reset process which uses a mailbox
command to synchronize the independent channels prior to the reset to
avoid the issue. Unfortunately, the timing windows required to ensure this
workaround succeeds are very specific, meaning we can't release the cpu
during the barrier.

Signed-off-by: James Smart <[email protected]>
Signed-off-by: James Bottomley <[email protected]>
  • Loading branch information
James Smart authored and James Bottomley committed Mar 12, 2006
1 parent 1a16968 commit 9290831
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 9 deletions.
1 change: 1 addition & 0 deletions drivers/scsi/lpfc/lpfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ struct lpfc_hba {
#define LPFC_HBA_READY 32
#define LPFC_HBA_ERROR -1

int32_t stopped; /* HBA has not been restarted since last ERATT */
uint8_t fc_linkspeed; /* Link speed after last READ_LA */

uint32_t fc_eventTag; /* event tag for link attention */
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/lpfc/lpfc_crtn.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);

void lpfc_reset_barrier(struct lpfc_hba * phba);
int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
int lpfc_sli_brdkill(struct lpfc_hba *);
int lpfc_sli_brdreset(struct lpfc_hba *);
Expand Down
4 changes: 3 additions & 1 deletion drivers/scsi/lpfc/lpfc_hbadisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ lpfc_work_list_done(struct lpfc_hba * phba)
case LPFC_EVT_WARM_START:
if (phba->hba_state >= LPFC_LINK_DOWN)
lpfc_offline(phba);
lpfc_reset_barrier(phba);
lpfc_sli_brdreset(phba);
lpfc_hba_down_post(phba);
*(int *)(evtp->evt_arg1) =
Expand All @@ -164,7 +165,8 @@ lpfc_work_list_done(struct lpfc_hba * phba)
case LPFC_EVT_KILL:
if (phba->hba_state >= LPFC_LINK_DOWN)
lpfc_offline(phba);
*(int *)(evtp->evt_arg1) = lpfc_sli_brdkill(phba);
*(int *)(evtp->evt_arg1)
= (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/lpfc/lpfc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,6 @@ lpfc_hba_down_prep(struct lpfc_hba * phba)
lpfc_els_flush_cmd(phba);
lpfc_disc_flush_list(phba);

/* Disable SLI2 since we disabled interrupts */
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
return (0);
}

Expand Down Expand Up @@ -526,6 +524,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
phba->work_status[0], phba->work_status[1]);
spin_lock_irq(phba->host->host_lock);
phba->fc_flag |= FC_ESTABLISH_LINK;
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
spin_unlock_irq(phba->host->host_lock);

/*
Expand Down Expand Up @@ -559,6 +558,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
phba->brd_no, phba->work_hs,
phba->work_status[0], phba->work_status[1]);

psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
lpfc_offline(phba);
phba->hba_state = LPFC_HBA_ERROR;
lpfc_hba_down_post(phba);
Expand Down
99 changes: 93 additions & 6 deletions drivers/scsi/lpfc/lpfc_sli.c
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,79 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
return retval;
}

#define BARRIER_TEST_PATTERN (0xdeadbeef)

void lpfc_reset_barrier(struct lpfc_hba * phba)
{
uint32_t * resp_buf;
uint32_t * mbox_buf;
volatile uint32_t mbox;
uint32_t hc_copy;
int i;
uint8_t hdrtype;

pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
if (hdrtype != 0x80 ||
(FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID))
return;

/*
* Tell the other part of the chip to suspend temporarily all
* its DMA activity.
*/
resp_buf = (uint32_t *)phba->MBslimaddr;

/* Disable the error attention */
hc_copy = readl(phba->HCregaddr);
writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
readl(phba->HCregaddr); /* flush */

if (readl(phba->HAregaddr) & HA_ERATT) {
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
phba->stopped = 1;
}

mbox = 0;
((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD;
((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;

writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
mbox_buf = (uint32_t *)phba->MBslimaddr;
writel(mbox, mbox_buf);

for (i = 0;
readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++)
mdelay(1);

if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
phba->stopped)
goto restore_hc;
else
goto clear_errat;
}

((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST;
for (i = 0; readl(resp_buf) != mbox && i < 500; i++)
mdelay(1);

clear_errat:

while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500)
mdelay(1);

if (readl(phba->HAregaddr) & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
phba->stopped = 1;
}

restore_hc:
writel(hc_copy, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}

int
lpfc_sli_brdkill(struct lpfc_hba * phba)
{
Expand All @@ -1588,9 +1661,8 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
psli->sli_flag);

if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_ATOMIC)) == 0) {
GFP_KERNEL)) == 0)
return 1;
}

/* Disable the error attention */
spin_lock_irq(phba->host->host_lock);
Expand All @@ -1610,6 +1682,8 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
return 1;
}

psli->sli_flag &= ~LPFC_SLI2_ACTIVE;

mempool_free(pmb, phba->mbox_mem_pool);

/* There is no completion for a KILL_BOARD mbox cmd. Check for an error
Expand All @@ -1625,7 +1699,10 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
}

del_timer_sync(&psli->mbox_tmo);

if (ha_copy & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
phba->stopped = 1;
}
spin_lock_irq(phba->host->host_lock);
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
spin_unlock_irq(phba->host->host_lock);
Expand Down Expand Up @@ -1665,6 +1742,7 @@ lpfc_sli_brdreset(struct lpfc_hba * phba)
(cfg_value &
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));

psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
/* Now toggle INITFF bit in the Host Control Register */
writel(HC_INITFF, phba->HCregaddr);
mdelay(1);
Expand Down Expand Up @@ -1713,6 +1791,8 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
mb->mbxCommand = MBX_RESTART;
mb->mbxHc = 1;

lpfc_reset_barrier(phba);

to_slim = phba->MBslimaddr;
writel(*(uint32_t *) mb, to_slim);
readl(to_slim); /* flush */
Expand All @@ -1730,7 +1810,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
readl(to_slim); /* flush */

lpfc_sli_brdreset(phba);

phba->stopped = 0;
phba->hba_state = LPFC_INIT_START;

spin_unlock_irq(phba->host->host_lock);
Expand Down Expand Up @@ -2038,6 +2118,13 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
return (MBX_NOT_FINISHED);
}

if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
!(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
return (MBX_NOT_FINISHED);
}

if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
/* Polling for a mbox command when another one is already active
* is not allowed in SLI. Also, the driver must have established
Expand Down Expand Up @@ -2154,8 +2241,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* First copy command data to host SLIM area */
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE);
} else {
if (mb->mbxCommand == MBX_CONFIG_PORT ||
mb->mbxCommand == MBX_KILL_BOARD) {
if (mb->mbxCommand == MBX_CONFIG_PORT) {
/* copy command data into host mbox for cmpl */
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
MAILBOX_CMD_SIZE);
Expand Down Expand Up @@ -3121,6 +3207,7 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
phba->stopped = 1;
}

spin_lock(phba->host->host_lock);
Expand Down

0 comments on commit 9290831

Please sign in to comment.