[SCSI] lpfc 8.1.2: Add ERROR and WARM_START modes for diagnostic purposes.
Add ERROR and WARM_START modes for diagnostic purposes. Signed-off-by: Jamie Wellnitz <Jamie.Wellnitz@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
Родитель
d9d959c41f
Коммит
41415862a2
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -175,25 +175,27 @@ struct lpfc_hba {
|
||||||
uint16_t pci_cfg_value;
|
uint16_t pci_cfg_value;
|
||||||
|
|
||||||
struct semaphore hba_can_block;
|
struct semaphore hba_can_block;
|
||||||
uint32_t hba_state;
|
int32_t hba_state;
|
||||||
|
|
||||||
#define LPFC_INIT_START 1 /* Initial state after board reset */
|
#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
|
||||||
#define LPFC_INIT_MBX_CMDS 2 /* Initialize HBA with mbox commands */
|
#define LPFC_WARM_START 1 /* HBA state after selective reset */
|
||||||
#define LPFC_LINK_DOWN 3 /* HBA initialized, link is down */
|
#define LPFC_INIT_START 2 /* Initial state after board reset */
|
||||||
#define LPFC_LINK_UP 4 /* Link is up - issue READ_LA */
|
#define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */
|
||||||
#define LPFC_LOCAL_CFG_LINK 5 /* local NPORT Id configured */
|
#define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */
|
||||||
#define LPFC_FLOGI 6 /* FLOGI sent to Fabric */
|
#define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */
|
||||||
#define LPFC_FABRIC_CFG_LINK 7 /* Fabric assigned NPORT Id
|
#define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */
|
||||||
|
#define LPFC_FLOGI 7 /* FLOGI sent to Fabric */
|
||||||
|
#define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id
|
||||||
configured */
|
configured */
|
||||||
#define LPFC_NS_REG 8 /* Register with NameServer */
|
#define LPFC_NS_REG 9 /* Register with NameServer */
|
||||||
#define LPFC_NS_QRY 9 /* Query NameServer for NPort ID list */
|
#define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */
|
||||||
#define LPFC_BUILD_DISC_LIST 10 /* Build ADISC and PLOGI lists for
|
#define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for
|
||||||
* device authentication / discovery */
|
* device authentication / discovery */
|
||||||
#define LPFC_DISC_AUTH 11 /* Processing ADISC list */
|
#define LPFC_DISC_AUTH 12 /* Processing ADISC list */
|
||||||
#define LPFC_CLEAR_LA 12 /* authentication cmplt - issue
|
#define LPFC_CLEAR_LA 13 /* authentication cmplt - issue
|
||||||
CLEAR_LA */
|
CLEAR_LA */
|
||||||
#define LPFC_HBA_READY 32
|
#define LPFC_HBA_READY 32
|
||||||
#define LPFC_HBA_ERROR 0xff
|
#define LPFC_HBA_ERROR -1
|
||||||
|
|
||||||
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
|
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -149,6 +149,8 @@ lpfc_state_show(struct class_device *cdev, char *buf)
|
||||||
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
|
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
switch (phba->hba_state) {
|
switch (phba->hba_state) {
|
||||||
|
case LPFC_STATE_UNKNOWN:
|
||||||
|
case LPFC_WARM_START:
|
||||||
case LPFC_INIT_START:
|
case LPFC_INIT_START:
|
||||||
case LPFC_INIT_MBX_CMDS:
|
case LPFC_INIT_MBX_CMDS:
|
||||||
case LPFC_LINK_DOWN:
|
case LPFC_LINK_DOWN:
|
||||||
|
@ -278,6 +280,58 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
lpfc_board_mode_show(struct class_device *cdev, char *buf)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *host = class_to_shost(cdev);
|
||||||
|
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
|
||||||
|
char * state;
|
||||||
|
|
||||||
|
if (phba->hba_state == LPFC_HBA_ERROR)
|
||||||
|
state = "error";
|
||||||
|
else if (phba->hba_state == LPFC_WARM_START)
|
||||||
|
state = "warm start";
|
||||||
|
else if (phba->hba_state == LPFC_INIT_START)
|
||||||
|
state = "offline";
|
||||||
|
else
|
||||||
|
state = "online";
|
||||||
|
|
||||||
|
return snprintf(buf, PAGE_SIZE, "%s\n", state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *host = class_to_shost(cdev);
|
||||||
|
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
|
||||||
|
struct completion online_compl;
|
||||||
|
int status=0;
|
||||||
|
|
||||||
|
init_completion(&online_compl);
|
||||||
|
|
||||||
|
if(strncmp(buf, "online", sizeof("online") - 1) == 0)
|
||||||
|
lpfc_workq_post_event(phba, &status, &online_compl,
|
||||||
|
LPFC_EVT_ONLINE);
|
||||||
|
else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
|
||||||
|
lpfc_workq_post_event(phba, &status, &online_compl,
|
||||||
|
LPFC_EVT_OFFLINE);
|
||||||
|
else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
|
||||||
|
lpfc_workq_post_event(phba, &status, &online_compl,
|
||||||
|
LPFC_EVT_WARM_START);
|
||||||
|
else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
|
||||||
|
lpfc_workq_post_event(phba, &status, &online_compl,
|
||||||
|
LPFC_EVT_KILL);
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
wait_for_completion(&online_compl);
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
return strlen(buf);
|
||||||
|
else
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
lpfc_poll_show(struct class_device *cdev, char *buf)
|
lpfc_poll_show(struct class_device *cdev, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -480,6 +534,8 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
|
||||||
NULL);
|
NULL);
|
||||||
static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
|
static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
|
||||||
lpfc_board_online_show, lpfc_board_online_store);
|
lpfc_board_online_show, lpfc_board_online_store);
|
||||||
|
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
|
||||||
|
lpfc_board_mode_show, lpfc_board_mode_store);
|
||||||
|
|
||||||
static int lpfc_poll = 0;
|
static int lpfc_poll = 0;
|
||||||
module_param(lpfc_poll, int, 0);
|
module_param(lpfc_poll, int, 0);
|
||||||
|
@ -674,6 +730,7 @@ struct class_device_attribute *lpfc_host_attrs[] = {
|
||||||
&class_device_attr_nport_evt_cnt,
|
&class_device_attr_nport_evt_cnt,
|
||||||
&class_device_attr_management_version,
|
&class_device_attr_management_version,
|
||||||
&class_device_attr_board_online,
|
&class_device_attr_board_online,
|
||||||
|
&class_device_attr_board_mode,
|
||||||
&class_device_attr_lpfc_poll,
|
&class_device_attr_lpfc_poll,
|
||||||
&class_device_attr_lpfc_poll_tmo,
|
&class_device_attr_lpfc_poll_tmo,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -883,8 +940,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||||
case MBX_DUMP_MEMORY:
|
case MBX_DUMP_MEMORY:
|
||||||
case MBX_DOWN_LOAD:
|
case MBX_DOWN_LOAD:
|
||||||
case MBX_UPDATE_CFG:
|
case MBX_UPDATE_CFG:
|
||||||
|
case MBX_KILL_BOARD:
|
||||||
case MBX_LOAD_AREA:
|
case MBX_LOAD_AREA:
|
||||||
case MBX_LOAD_EXP_ROM:
|
case MBX_LOAD_EXP_ROM:
|
||||||
|
case MBX_BEACON:
|
||||||
|
case MBX_DEL_LD_ENTRY:
|
||||||
break;
|
break;
|
||||||
case MBX_READ_SPARM64:
|
case MBX_READ_SPARM64:
|
||||||
case MBX_READ_LA:
|
case MBX_READ_LA:
|
||||||
|
@ -1042,6 +1102,8 @@ lpfc_get_host_port_state(struct Scsi_Host *shost)
|
||||||
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
|
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
|
||||||
else {
|
else {
|
||||||
switch (phba->hba_state) {
|
switch (phba->hba_state) {
|
||||||
|
case LPFC_STATE_UNKNOWN:
|
||||||
|
case LPFC_WARM_START:
|
||||||
case LPFC_INIT_START:
|
case LPFC_INIT_START:
|
||||||
case LPFC_INIT_MBX_CMDS:
|
case LPFC_INIT_MBX_CMDS:
|
||||||
case LPFC_LINK_DOWN:
|
case LPFC_LINK_DOWN:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* *
|
* *
|
||||||
|
@ -107,6 +107,7 @@ void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
|
||||||
int lpfc_config_port_prep(struct lpfc_hba *);
|
int lpfc_config_port_prep(struct lpfc_hba *);
|
||||||
int lpfc_config_port_post(struct lpfc_hba *);
|
int lpfc_config_port_post(struct lpfc_hba *);
|
||||||
int lpfc_hba_down_prep(struct lpfc_hba *);
|
int lpfc_hba_down_prep(struct lpfc_hba *);
|
||||||
|
int lpfc_hba_down_post(struct lpfc_hba *);
|
||||||
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
|
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
|
||||||
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
|
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
|
||||||
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
|
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
|
||||||
|
@ -123,6 +124,7 @@ irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
|
||||||
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||||
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
|
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
|
||||||
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||||
|
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||||
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||||
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
|
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
|
||||||
|
|
||||||
|
@ -135,6 +137,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
|
||||||
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
|
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
|
||||||
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
|
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);
|
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
|
||||||
|
|
||||||
|
int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
|
||||||
|
int lpfc_sli_brdkill(struct lpfc_hba *);
|
||||||
|
int lpfc_sli_brdreset(struct lpfc_hba *);
|
||||||
|
int lpfc_sli_brdrestart(struct lpfc_hba *);
|
||||||
int lpfc_sli_hba_setup(struct lpfc_hba *);
|
int lpfc_sli_hba_setup(struct lpfc_hba *);
|
||||||
int lpfc_sli_hba_down(struct lpfc_hba *);
|
int lpfc_sli_hba_down(struct lpfc_hba *);
|
||||||
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
|
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* *
|
* *
|
||||||
|
@ -28,18 +28,24 @@
|
||||||
* This is used by Fibre Channel protocol to support FCP.
|
* This is used by Fibre Channel protocol to support FCP.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* worker thread events */
|
||||||
|
enum lpfc_work_type {
|
||||||
|
LPFC_EVT_NODEV_TMO,
|
||||||
|
LPFC_EVT_ONLINE,
|
||||||
|
LPFC_EVT_OFFLINE,
|
||||||
|
LPFC_EVT_WARM_START,
|
||||||
|
LPFC_EVT_KILL,
|
||||||
|
LPFC_EVT_ELS_RETRY,
|
||||||
|
};
|
||||||
|
|
||||||
/* structure used to queue event to the discovery tasklet */
|
/* structure used to queue event to the discovery tasklet */
|
||||||
struct lpfc_work_evt {
|
struct lpfc_work_evt {
|
||||||
struct list_head evt_listp;
|
struct list_head evt_listp;
|
||||||
void * evt_arg1;
|
void * evt_arg1;
|
||||||
void * evt_arg2;
|
void * evt_arg2;
|
||||||
uint32_t evt;
|
enum lpfc_work_type evt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LPFC_EVT_NODEV_TMO 0x1
|
|
||||||
#define LPFC_EVT_ONLINE 0x2
|
|
||||||
#define LPFC_EVT_OFFLINE 0x3
|
|
||||||
#define LPFC_EVT_ELS_RETRY 0x4
|
|
||||||
|
|
||||||
struct lpfc_nodelist {
|
struct lpfc_nodelist {
|
||||||
struct list_head nlp_listp;
|
struct list_head nlp_listp;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -120,11 +120,33 @@ lpfc_work_list_done(struct lpfc_hba * phba)
|
||||||
free_evt = 0;
|
free_evt = 0;
|
||||||
break;
|
break;
|
||||||
case LPFC_EVT_ONLINE:
|
case LPFC_EVT_ONLINE:
|
||||||
|
if (phba->hba_state < LPFC_LINK_DOWN)
|
||||||
*(int *)(evtp->evt_arg1) = lpfc_online(phba);
|
*(int *)(evtp->evt_arg1) = lpfc_online(phba);
|
||||||
|
else
|
||||||
|
*(int *)(evtp->evt_arg1) = 0;
|
||||||
complete((struct completion *)(evtp->evt_arg2));
|
complete((struct completion *)(evtp->evt_arg2));
|
||||||
break;
|
break;
|
||||||
case LPFC_EVT_OFFLINE:
|
case LPFC_EVT_OFFLINE:
|
||||||
*(int *)(evtp->evt_arg1) = lpfc_offline(phba);
|
if (phba->hba_state >= LPFC_LINK_DOWN)
|
||||||
|
lpfc_offline(phba);
|
||||||
|
lpfc_sli_brdrestart(phba);
|
||||||
|
*(int *)(evtp->evt_arg1) =
|
||||||
|
lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY);
|
||||||
|
complete((struct completion *)(evtp->evt_arg2));
|
||||||
|
break;
|
||||||
|
case LPFC_EVT_WARM_START:
|
||||||
|
if (phba->hba_state >= LPFC_LINK_DOWN)
|
||||||
|
lpfc_offline(phba);
|
||||||
|
lpfc_sli_brdreset(phba);
|
||||||
|
lpfc_hba_down_post(phba);
|
||||||
|
*(int *)(evtp->evt_arg1) =
|
||||||
|
lpfc_sli_brdready(phba, HS_MBRDY);
|
||||||
|
complete((struct completion *)(evtp->evt_arg2));
|
||||||
|
break;
|
||||||
|
case LPFC_EVT_KILL:
|
||||||
|
if (phba->hba_state >= LPFC_LINK_DOWN)
|
||||||
|
lpfc_offline(phba);
|
||||||
|
*(int *)(evtp->evt_arg1) = lpfc_sli_brdkill(phba);
|
||||||
complete((struct completion *)(evtp->evt_arg2));
|
complete((struct completion *)(evtp->evt_arg2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -287,6 +309,10 @@ lpfc_linkdown(struct lpfc_hba * phba)
|
||||||
LPFC_MBOXQ_t *mb;
|
LPFC_MBOXQ_t *mb;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
|
|
||||||
|
if (phba->hba_state == LPFC_LINK_DOWN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
psli = &phba->sli;
|
psli = &phba->sli;
|
||||||
|
|
||||||
/* sysfs or selective reset may call this routine to clean up */
|
/* sysfs or selective reset may call this routine to clean up */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* *
|
* *
|
||||||
|
@ -1233,7 +1233,9 @@ typedef struct { /* FireFly BIU registers */
|
||||||
#define MBX_SET_MASK 0x20
|
#define MBX_SET_MASK 0x20
|
||||||
#define MBX_SET_SLIM 0x21
|
#define MBX_SET_SLIM 0x21
|
||||||
#define MBX_UNREG_D_ID 0x23
|
#define MBX_UNREG_D_ID 0x23
|
||||||
|
#define MBX_KILL_BOARD 0x24
|
||||||
#define MBX_CONFIG_FARP 0x25
|
#define MBX_CONFIG_FARP 0x25
|
||||||
|
#define MBX_BEACON 0x2A
|
||||||
|
|
||||||
#define MBX_LOAD_AREA 0x81
|
#define MBX_LOAD_AREA 0x81
|
||||||
#define MBX_RUN_BIU_DIAG64 0x84
|
#define MBX_RUN_BIU_DIAG64 0x84
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -459,9 +459,45 @@ lpfc_hba_down_prep(struct lpfc_hba * phba)
|
||||||
lpfc_els_flush_cmd(phba);
|
lpfc_els_flush_cmd(phba);
|
||||||
lpfc_disc_flush_list(phba);
|
lpfc_disc_flush_list(phba);
|
||||||
|
|
||||||
|
/* Disable SLI2 since we disabled interrupts */
|
||||||
|
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* lpfc_hba_down_post */
|
||||||
|
/* This routine will do uninitialization after the HBA is reset */
|
||||||
|
/* when bringing down the SLI Layer. */
|
||||||
|
/* This routine returns 0 on success. Any other return value */
|
||||||
|
/* indicates an error. */
|
||||||
|
/* */
|
||||||
|
/************************************************************************/
|
||||||
|
int
|
||||||
|
lpfc_hba_down_post(struct lpfc_hba * phba)
|
||||||
|
{
|
||||||
|
struct lpfc_sli *psli = &phba->sli;
|
||||||
|
struct lpfc_sli_ring *pring;
|
||||||
|
struct lpfc_dmabuf *mp, *next_mp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Cleanup preposted buffers on the ELS ring */
|
||||||
|
pring = &psli->ring[LPFC_ELS_RING];
|
||||||
|
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
|
||||||
|
list_del(&mp->list);
|
||||||
|
pring->postbufq_cnt--;
|
||||||
|
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
||||||
|
kfree(mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < psli->num_rings; i++) {
|
||||||
|
pring = &psli->ring[i];
|
||||||
|
lpfc_sli_abort_iocb_ring(phba, pring);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* lpfc_handle_eratt */
|
/* lpfc_handle_eratt */
|
||||||
|
@ -476,20 +512,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
|
||||||
struct lpfc_sli *psli = &phba->sli;
|
struct lpfc_sli *psli = &phba->sli;
|
||||||
struct lpfc_sli_ring *pring;
|
struct lpfc_sli_ring *pring;
|
||||||
|
|
||||||
/*
|
|
||||||
* If a reset is sent to the HBA restore PCI configuration registers.
|
|
||||||
*/
|
|
||||||
if ( phba->hba_state == LPFC_INIT_START ) {
|
|
||||||
mdelay(1);
|
|
||||||
readl(phba->HCregaddr); /* flush */
|
|
||||||
writel(0, phba->HCregaddr);
|
|
||||||
readl(phba->HCregaddr); /* flush */
|
|
||||||
|
|
||||||
/* Restore PCI cmd register */
|
|
||||||
pci_write_config_word(phba->pcidev,
|
|
||||||
PCI_COMMAND, phba->pci_cfg_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phba->work_hs & HS_FFER6) {
|
if (phba->work_hs & HS_FFER6) {
|
||||||
/* Re-establishing Link */
|
/* Re-establishing Link */
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
|
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
|
||||||
|
@ -516,6 +538,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
|
||||||
* attempt to restart it.
|
* attempt to restart it.
|
||||||
*/
|
*/
|
||||||
lpfc_offline(phba);
|
lpfc_offline(phba);
|
||||||
|
lpfc_sli_brdrestart(phba);
|
||||||
if (lpfc_online(phba) == 0) { /* Initialize the HBA */
|
if (lpfc_online(phba) == 0) { /* Initialize the HBA */
|
||||||
mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
|
mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
|
||||||
return;
|
return;
|
||||||
|
@ -532,7 +555,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
|
||||||
phba->work_status[0], phba->work_status[1]);
|
phba->work_status[0], phba->work_status[1]);
|
||||||
|
|
||||||
lpfc_offline(phba);
|
lpfc_offline(phba);
|
||||||
|
phba->hba_state = LPFC_HBA_ERROR;
|
||||||
|
lpfc_hba_down_post(phba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1695,6 +1719,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
|
||||||
* the HBA.
|
* the HBA.
|
||||||
*/
|
*/
|
||||||
lpfc_sli_hba_down(phba);
|
lpfc_sli_hba_down(phba);
|
||||||
|
lpfc_sli_brdrestart(phba);
|
||||||
|
|
||||||
/* Release the irq reservation */
|
/* Release the irq reservation */
|
||||||
free_irq(phba->pcidev->irq, phba);
|
free_irq(phba->pcidev->irq, phba);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -636,6 +636,17 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||||
phba->brd_no);
|
phba->brd_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||||
|
{
|
||||||
|
MAILBOX_t *mb = &pmb->mb;
|
||||||
|
|
||||||
|
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
|
||||||
|
mb->mbxCommand = MBX_KILL_BOARD;
|
||||||
|
mb->mbxOwner = OWN_HOST;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
|
lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2004-2005 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
* www.emulex.com *
|
* www.emulex.com *
|
||||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||||
|
@ -513,7 +513,9 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
|
||||||
case MBX_SET_MASK:
|
case MBX_SET_MASK:
|
||||||
case MBX_SET_SLIM:
|
case MBX_SET_SLIM:
|
||||||
case MBX_UNREG_D_ID:
|
case MBX_UNREG_D_ID:
|
||||||
|
case MBX_KILL_BOARD:
|
||||||
case MBX_CONFIG_FARP:
|
case MBX_CONFIG_FARP:
|
||||||
|
case MBX_BEACON:
|
||||||
case MBX_LOAD_AREA:
|
case MBX_LOAD_AREA:
|
||||||
case MBX_RUN_BIU_DIAG64:
|
case MBX_RUN_BIU_DIAG64:
|
||||||
case MBX_CONFIG_PORT:
|
case MBX_CONFIG_PORT:
|
||||||
|
@ -1512,98 +1514,162 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
|
||||||
return errcnt;
|
return errcnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
int
|
||||||
* lpfc_sli_send_reset
|
lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
|
||||||
*
|
|
||||||
* Note: After returning from this function, the HBA cannot be accessed for
|
|
||||||
* 1 ms. Since we do not wish to delay in interrupt context, it is the
|
|
||||||
* responsibility of the caller to perform the mdelay(1) and flush via readl().
|
|
||||||
******************************************************************************/
|
|
||||||
static int
|
|
||||||
lpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post)
|
|
||||||
{
|
{
|
||||||
MAILBOX_t *swpmb;
|
uint32_t status;
|
||||||
volatile uint32_t word0;
|
int i = 0;
|
||||||
void __iomem *to_slim;
|
int retval = 0;
|
||||||
unsigned long flags = 0;
|
|
||||||
|
|
||||||
spin_lock_irqsave(phba->host->host_lock, flags);
|
/* Read the HBA Host Status Register */
|
||||||
|
status = readl(phba->HSregaddr);
|
||||||
|
|
||||||
/* A board reset must use REAL SLIM. */
|
/*
|
||||||
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
|
* Check status register every 100ms for 5 retries, then every
|
||||||
|
* 500ms for 5, then every 2.5 sec for 5, then reset board and
|
||||||
|
* every 2.5 sec for 4.
|
||||||
|
* Break our of the loop if errors occurred during init.
|
||||||
|
*/
|
||||||
|
while (((status & mask) != mask) &&
|
||||||
|
!(status & HS_FFERM) &&
|
||||||
|
i++ < 20) {
|
||||||
|
|
||||||
word0 = 0;
|
if (i <= 5)
|
||||||
swpmb = (MAILBOX_t *) & word0;
|
msleep(10);
|
||||||
swpmb->mbxCommand = MBX_RESTART;
|
else if (i <= 10)
|
||||||
swpmb->mbxHc = 1;
|
msleep(500);
|
||||||
|
else
|
||||||
|
msleep(2500);
|
||||||
|
|
||||||
to_slim = phba->MBslimaddr;
|
if (i == 15) {
|
||||||
writel(*(uint32_t *) swpmb, to_slim);
|
phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
|
||||||
readl(to_slim); /* flush */
|
lpfc_sli_brdrestart(phba);
|
||||||
|
|
||||||
/* Only skip post after fc_ffinit is completed */
|
|
||||||
if (skip_post) {
|
|
||||||
word0 = 1; /* This is really setting up word1 */
|
|
||||||
} else {
|
|
||||||
word0 = 0; /* This is really setting up word1 */
|
|
||||||
}
|
}
|
||||||
to_slim = phba->MBslimaddr + sizeof (uint32_t);
|
/* Read the HBA Host Status Register */
|
||||||
writel(*(uint32_t *) swpmb, to_slim);
|
status = readl(phba->HSregaddr);
|
||||||
readl(to_slim); /* flush */
|
|
||||||
|
|
||||||
/* Turn off parity checking and serr during the physical reset */
|
|
||||||
pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value);
|
|
||||||
pci_write_config_word(phba->pcidev, PCI_COMMAND,
|
|
||||||
(phba->pci_cfg_value &
|
|
||||||
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
|
|
||||||
|
|
||||||
writel(HC_INITFF, phba->HCregaddr);
|
|
||||||
|
|
||||||
phba->hba_state = LPFC_INIT_START;
|
|
||||||
spin_unlock_irqrestore(phba->host->host_lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/* Check to see if any errors occurred during init */
|
||||||
lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post)
|
if ((status & HS_FFERM) || (i >= 20)) {
|
||||||
|
phba->hba_state = LPFC_HBA_ERROR;
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lpfc_sli_brdkill(struct lpfc_hba * phba)
|
||||||
{
|
{
|
||||||
|
struct lpfc_sli *psli;
|
||||||
|
LPFC_MBOXQ_t *pmb;
|
||||||
|
uint32_t status;
|
||||||
|
uint32_t ha_copy;
|
||||||
|
int retval;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
psli = &phba->sli;
|
||||||
|
|
||||||
|
/* Kill HBA */
|
||||||
|
lpfc_printf_log(phba,
|
||||||
|
KERN_INFO,
|
||||||
|
LOG_SLI,
|
||||||
|
"%d:0329 Kill HBA Data: x%x x%x\n",
|
||||||
|
phba->brd_no,
|
||||||
|
phba->hba_state,
|
||||||
|
psli->sli_flag);
|
||||||
|
|
||||||
|
if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
|
||||||
|
GFP_ATOMIC)) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable the error attention */
|
||||||
|
spin_lock_irq(phba->host->host_lock);
|
||||||
|
status = readl(phba->HCregaddr);
|
||||||
|
status &= ~HC_ERINT_ENA;
|
||||||
|
writel(status, phba->HCregaddr);
|
||||||
|
readl(phba->HCregaddr); /* flush */
|
||||||
|
spin_unlock_irq(phba->host->host_lock);
|
||||||
|
|
||||||
|
lpfc_kill_board(phba, pmb);
|
||||||
|
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||||
|
retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
|
||||||
|
|
||||||
|
if (retval != MBX_SUCCESS) {
|
||||||
|
if (retval != MBX_BUSY)
|
||||||
|
mempool_free(pmb, phba->mbox_mem_pool);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mempool_free(pmb, phba->mbox_mem_pool);
|
||||||
|
|
||||||
|
/* There is no completion for a KILL_BOARD mbox cmd. Check for an error
|
||||||
|
* attention every 100ms for 3 seconds. If we don't get ERATT after
|
||||||
|
* 3 seconds we still set HBA_ERROR state because the status of the
|
||||||
|
* board is now undefined.
|
||||||
|
*/
|
||||||
|
ha_copy = readl(phba->HAregaddr);
|
||||||
|
|
||||||
|
while ((i++ < 30) && !(ha_copy & HA_ERATT)) {
|
||||||
|
mdelay(100);
|
||||||
|
ha_copy = readl(phba->HAregaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
del_timer_sync(&psli->mbox_tmo);
|
||||||
|
|
||||||
|
spin_lock_irq(phba->host->host_lock);
|
||||||
|
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
||||||
|
spin_unlock_irq(phba->host->host_lock);
|
||||||
|
|
||||||
|
psli->mbox_active = NULL;
|
||||||
|
lpfc_hba_down_post(phba);
|
||||||
|
phba->hba_state = LPFC_HBA_ERROR;
|
||||||
|
|
||||||
|
return (ha_copy & HA_ERATT ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lpfc_sli_brdreset(struct lpfc_hba * phba)
|
||||||
|
{
|
||||||
|
struct lpfc_sli *psli;
|
||||||
struct lpfc_sli_ring *pring;
|
struct lpfc_sli_ring *pring;
|
||||||
|
uint16_t cfg_value;
|
||||||
int i;
|
int i;
|
||||||
struct lpfc_dmabuf *mp, *next_mp;
|
|
||||||
unsigned long flags = 0;
|
|
||||||
|
|
||||||
lpfc_sli_send_reset(phba, skip_post);
|
psli = &phba->sli;
|
||||||
mdelay(1);
|
|
||||||
|
|
||||||
spin_lock_irqsave(phba->host->host_lock, flags);
|
/* Reset HBA */
|
||||||
/* Risk the write on flush case ie no delay after the readl */
|
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||||
readl(phba->HCregaddr); /* flush */
|
"%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
|
||||||
/* Now toggle INITFF bit set by lpfc_sli_send_reset */
|
phba->hba_state, psli->sli_flag);
|
||||||
writel(0, phba->HCregaddr);
|
|
||||||
readl(phba->HCregaddr); /* flush */
|
|
||||||
|
|
||||||
/* Restore PCI cmd register */
|
|
||||||
pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value);
|
|
||||||
|
|
||||||
/* perform board reset */
|
/* perform board reset */
|
||||||
phba->fc_eventTag = 0;
|
phba->fc_eventTag = 0;
|
||||||
phba->fc_myDID = 0;
|
phba->fc_myDID = 0;
|
||||||
phba->fc_prevDID = Mask_DID;
|
phba->fc_prevDID = 0;
|
||||||
|
|
||||||
/* Reset HBA */
|
psli->sli_flag = 0;
|
||||||
lpfc_printf_log(phba,
|
|
||||||
KERN_INFO,
|
/* Turn off parity checking and serr during the physical reset */
|
||||||
LOG_SLI,
|
pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
|
||||||
"%d:0325 Reset HBA Data: x%x x%x x%x\n",
|
pci_write_config_word(phba->pcidev, PCI_COMMAND,
|
||||||
phba->brd_no,
|
(cfg_value &
|
||||||
phba->hba_state,
|
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
|
||||||
phba->sli.sli_flag,
|
|
||||||
skip_post);
|
/* Now toggle INITFF bit in the Host Control Register */
|
||||||
|
writel(HC_INITFF, phba->HCregaddr);
|
||||||
|
mdelay(1);
|
||||||
|
readl(phba->HCregaddr); /* flush */
|
||||||
|
writel(0, phba->HCregaddr);
|
||||||
|
readl(phba->HCregaddr); /* flush */
|
||||||
|
|
||||||
|
/* Restore PCI cmd register */
|
||||||
|
pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
|
||||||
|
|
||||||
/* Initialize relevant SLI info */
|
/* Initialize relevant SLI info */
|
||||||
for (i = 0; i < phba->sli.num_rings; i++) {
|
for (i = 0; i < psli->num_rings; i++) {
|
||||||
pring = &phba->sli.ring[i];
|
pring = &psli->ring[i];
|
||||||
pring->flag = 0;
|
pring->flag = 0;
|
||||||
pring->rspidx = 0;
|
pring->rspidx = 0;
|
||||||
pring->next_cmdidx = 0;
|
pring->next_cmdidx = 0;
|
||||||
|
@ -1611,27 +1677,62 @@ lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post)
|
||||||
pring->cmdidx = 0;
|
pring->cmdidx = 0;
|
||||||
pring->missbufcnt = 0;
|
pring->missbufcnt = 0;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(phba->host->host_lock, flags);
|
|
||||||
|
|
||||||
if (skip_post) {
|
phba->hba_state = LPFC_WARM_START;
|
||||||
mdelay(100);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lpfc_sli_brdrestart(struct lpfc_hba * phba)
|
||||||
|
{
|
||||||
|
MAILBOX_t *mb;
|
||||||
|
struct lpfc_sli *psli;
|
||||||
|
uint16_t skip_post;
|
||||||
|
volatile uint32_t word0;
|
||||||
|
void __iomem *to_slim;
|
||||||
|
|
||||||
|
spin_lock_irq(phba->host->host_lock);
|
||||||
|
|
||||||
|
psli = &phba->sli;
|
||||||
|
|
||||||
|
/* Restart HBA */
|
||||||
|
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||||
|
"%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no,
|
||||||
|
phba->hba_state, psli->sli_flag);
|
||||||
|
|
||||||
|
word0 = 0;
|
||||||
|
mb = (MAILBOX_t *) &word0;
|
||||||
|
mb->mbxCommand = MBX_RESTART;
|
||||||
|
mb->mbxHc = 1;
|
||||||
|
|
||||||
|
to_slim = phba->MBslimaddr;
|
||||||
|
writel(*(uint32_t *) mb, to_slim);
|
||||||
|
readl(to_slim); /* flush */
|
||||||
|
|
||||||
|
/* Only skip post after fc_ffinit is completed */
|
||||||
|
if (phba->hba_state) {
|
||||||
|
skip_post = 1;
|
||||||
|
word0 = 1; /* This is really setting up word1 */
|
||||||
} else {
|
} else {
|
||||||
|
skip_post = 0;
|
||||||
|
word0 = 0; /* This is really setting up word1 */
|
||||||
|
}
|
||||||
|
to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t);
|
||||||
|
writel(*(uint32_t *) mb, to_slim);
|
||||||
|
readl(to_slim); /* flush */
|
||||||
|
|
||||||
|
lpfc_sli_brdreset(phba);
|
||||||
|
|
||||||
|
phba->hba_state = LPFC_INIT_START;
|
||||||
|
|
||||||
|
spin_unlock_irq(phba->host->host_lock);
|
||||||
|
|
||||||
|
if (skip_post)
|
||||||
|
mdelay(100);
|
||||||
|
else
|
||||||
mdelay(2000);
|
mdelay(2000);
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(phba->host->host_lock, flags);
|
lpfc_hba_down_post(phba);
|
||||||
/* Cleanup preposted buffers on the ELS ring */
|
|
||||||
pring = &phba->sli.ring[LPFC_ELS_RING];
|
|
||||||
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
|
|
||||||
list_del(&mp->list);
|
|
||||||
pring->postbufq_cnt--;
|
|
||||||
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
|
||||||
kfree(mp);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(phba->host->host_lock, flags);
|
|
||||||
|
|
||||||
for (i = 0; i < phba->sli.num_rings; i++)
|
|
||||||
lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1691,7 +1792,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 15) {
|
if (i == 15) {
|
||||||
lpfc_sli_brdreset(phba, 0);
|
phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
|
||||||
|
lpfc_sli_brdrestart(phba);
|
||||||
}
|
}
|
||||||
/* Read the HBA Host Status Register */
|
/* Read the HBA Host Status Register */
|
||||||
status = readl(phba->HSregaddr);
|
status = readl(phba->HSregaddr);
|
||||||
|
@ -1735,8 +1837,8 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (resetcount < 2 && !done) {
|
while (resetcount < 2 && !done) {
|
||||||
phba->hba_state = 0;
|
phba->hba_state = LPFC_STATE_UNKNOWN;
|
||||||
lpfc_sli_brdreset(phba, 0);
|
lpfc_sli_brdrestart(phba);
|
||||||
msleep(2500);
|
msleep(2500);
|
||||||
rc = lpfc_sli_chipset_init(phba);
|
rc = lpfc_sli_chipset_init(phba);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1920,6 +2022,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
|
||||||
mb = &pmbox->mb;
|
mb = &pmbox->mb;
|
||||||
status = MBX_SUCCESS;
|
status = MBX_SUCCESS;
|
||||||
|
|
||||||
|
if (phba->hba_state == LPFC_HBA_ERROR) {
|
||||||
|
spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
|
||||||
|
|
||||||
|
/* Mbox command <mbxCommand> cannot issue */
|
||||||
|
LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
|
||||||
|
return (MBX_NOT_FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
|
if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
|
||||||
/* Polling for a mbox command when another one is already active
|
/* Polling for a mbox command when another one is already active
|
||||||
* is not allowed in SLI. Also, the driver must have established
|
* is not allowed in SLI. Also, the driver must have established
|
||||||
|
@ -2002,7 +2112,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
|
||||||
|
|
||||||
/* If we are not polling, we MUST be in SLI2 mode */
|
/* If we are not polling, we MUST be in SLI2 mode */
|
||||||
if (flag != MBX_POLL) {
|
if (flag != MBX_POLL) {
|
||||||
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
|
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
|
||||||
|
(mb->mbxCommand != MBX_KILL_BOARD)) {
|
||||||
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
||||||
spin_unlock_irqrestore(phba->host->host_lock,
|
spin_unlock_irqrestore(phba->host->host_lock,
|
||||||
drvr_flag);
|
drvr_flag);
|
||||||
|
@ -2035,7 +2146,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
|
||||||
/* First copy command data to host SLIM area */
|
/* First copy command data to host SLIM area */
|
||||||
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE);
|
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE);
|
||||||
} else {
|
} else {
|
||||||
if (mb->mbxCommand == MBX_CONFIG_PORT) {
|
if (mb->mbxCommand == MBX_CONFIG_PORT ||
|
||||||
|
mb->mbxCommand == MBX_KILL_BOARD) {
|
||||||
/* copy command data into host mbox for cmpl */
|
/* copy command data into host mbox for cmpl */
|
||||||
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
|
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
|
||||||
MAILBOX_CMD_SIZE);
|
MAILBOX_CMD_SIZE);
|
||||||
|
@ -2086,8 +2198,9 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
|
||||||
ha_copy = readl(phba->HAregaddr);
|
ha_copy = readl(phba->HAregaddr);
|
||||||
|
|
||||||
/* Wait for command to complete */
|
/* Wait for command to complete */
|
||||||
while (((word0 & OWN_CHIP) == OWN_CHIP)
|
while (((word0 & OWN_CHIP) == OWN_CHIP) ||
|
||||||
|| !(ha_copy & HA_MBATT)) {
|
(!(ha_copy & HA_MBATT) &&
|
||||||
|
(phba->hba_state > LPFC_WARM_START))) {
|
||||||
if (i++ >= 100) {
|
if (i++ >= 100) {
|
||||||
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
||||||
spin_unlock_irqrestore(phba->host->host_lock,
|
spin_unlock_irqrestore(phba->host->host_lock,
|
||||||
|
@ -2455,15 +2568,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
|
||||||
|
|
||||||
spin_unlock_irqrestore(phba->host->host_lock, flags);
|
spin_unlock_irqrestore(phba->host->host_lock, flags);
|
||||||
|
|
||||||
/*
|
|
||||||
* Provided the hba is not in an error state, reset it. It is not
|
|
||||||
* capable of IO anymore.
|
|
||||||
*/
|
|
||||||
if (phba->hba_state != LPFC_HBA_ERROR) {
|
|
||||||
phba->hba_state = LPFC_INIT_START;
|
|
||||||
lpfc_sli_brdreset(phba, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2976,13 +3080,6 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
|
||||||
/* Clear Chip error bit */
|
/* Clear Chip error bit */
|
||||||
writel(HA_ERATT, phba->HAregaddr);
|
writel(HA_ERATT, phba->HAregaddr);
|
||||||
readl(phba->HAregaddr); /* flush */
|
readl(phba->HAregaddr); /* flush */
|
||||||
|
|
||||||
/*
|
|
||||||
* Reseting the HBA is the only reliable way
|
|
||||||
* to shutdown interrupt when there is a
|
|
||||||
* ERROR.
|
|
||||||
*/
|
|
||||||
lpfc_sli_send_reset(phba, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(phba->host->host_lock);
|
spin_lock(phba->host->host_lock);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче