diff options
author | Jamie Wellnitz <Jamie.Wellnitz@emulex.com> | 2006-02-28 19:25:27 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-02-28 20:00:36 -0500 |
commit | 41415862a23f422b80eccc92cf885935139e2415 (patch) | |
tree | e3a9537653e472f15405778c4dcc678a56304848 | |
parent | d9d959c41f013439508e0fa1d31f5644d8d626ef (diff) |
[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>
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 34 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 64 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 32 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 57 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 13 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 311 |
9 files changed, 390 insertions, 152 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 214ab436e035..c4cca9124f45 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -175,25 +175,27 @@ struct lpfc_hba { | |||
175 | uint16_t pci_cfg_value; | 175 | uint16_t pci_cfg_value; |
176 | 176 | ||
177 | struct semaphore hba_can_block; | 177 | struct semaphore hba_can_block; |
178 | uint32_t hba_state; | 178 | int32_t hba_state; |
179 | 179 | ||
180 | #define LPFC_INIT_START 1 /* Initial state after board reset */ | 180 | #define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */ |
181 | #define LPFC_INIT_MBX_CMDS 2 /* Initialize HBA with mbox commands */ | 181 | #define LPFC_WARM_START 1 /* HBA state after selective reset */ |
182 | #define LPFC_LINK_DOWN 3 /* HBA initialized, link is down */ | 182 | #define LPFC_INIT_START 2 /* Initial state after board reset */ |
183 | #define LPFC_LINK_UP 4 /* Link is up - issue READ_LA */ | 183 | #define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */ |
184 | #define LPFC_LOCAL_CFG_LINK 5 /* local NPORT Id configured */ | 184 | #define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */ |
185 | #define LPFC_FLOGI 6 /* FLOGI sent to Fabric */ | 185 | #define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */ |
186 | #define LPFC_FABRIC_CFG_LINK 7 /* Fabric assigned NPORT Id | 186 | #define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */ |
187 | #define LPFC_FLOGI 7 /* FLOGI sent to Fabric */ | ||
188 | #define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id | ||
187 | configured */ | 189 | configured */ |
188 | #define LPFC_NS_REG 8 /* Register with NameServer */ | 190 | #define LPFC_NS_REG 9 /* Register with NameServer */ |
189 | #define LPFC_NS_QRY 9 /* Query NameServer for NPort ID list */ | 191 | #define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */ |
190 | #define LPFC_BUILD_DISC_LIST 10 /* Build ADISC and PLOGI lists for | 192 | #define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for |
191 | * device authentication / discovery */ | 193 | * device authentication / discovery */ |
192 | #define LPFC_DISC_AUTH 11 /* Processing ADISC list */ | 194 | #define LPFC_DISC_AUTH 12 /* Processing ADISC list */ |
193 | #define LPFC_CLEAR_LA 12 /* authentication cmplt - issue | 195 | #define LPFC_CLEAR_LA 13 /* authentication cmplt - issue |
194 | CLEAR_LA */ | 196 | CLEAR_LA */ |
195 | #define LPFC_HBA_READY 32 | 197 | #define LPFC_HBA_READY 32 |
196 | #define LPFC_HBA_ERROR 0xff | 198 | #define LPFC_HBA_ERROR -1 |
197 | 199 | ||
198 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ | 200 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ |
199 | 201 | ||
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c8fb43d60882..e7aca3c4b26e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -149,6 +149,8 @@ lpfc_state_show(struct class_device *cdev, char *buf) | |||
149 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; | 149 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; |
150 | int len = 0; | 150 | int len = 0; |
151 | switch (phba->hba_state) { | 151 | switch (phba->hba_state) { |
152 | case LPFC_STATE_UNKNOWN: | ||
153 | case LPFC_WARM_START: | ||
152 | case LPFC_INIT_START: | 154 | case LPFC_INIT_START: |
153 | case LPFC_INIT_MBX_CMDS: | 155 | case LPFC_INIT_MBX_CMDS: |
154 | case LPFC_LINK_DOWN: | 156 | case LPFC_LINK_DOWN: |
@@ -279,6 +281,58 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf, | |||
279 | } | 281 | } |
280 | 282 | ||
281 | static ssize_t | 283 | static ssize_t |
284 | lpfc_board_mode_show(struct class_device *cdev, char *buf) | ||
285 | { | ||
286 | struct Scsi_Host *host = class_to_shost(cdev); | ||
287 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; | ||
288 | char * state; | ||
289 | |||
290 | if (phba->hba_state == LPFC_HBA_ERROR) | ||
291 | state = "error"; | ||
292 | else if (phba->hba_state == LPFC_WARM_START) | ||
293 | state = "warm start"; | ||
294 | else if (phba->hba_state == LPFC_INIT_START) | ||
295 | state = "offline"; | ||
296 | else | ||
297 | state = "online"; | ||
298 | |||
299 | return snprintf(buf, PAGE_SIZE, "%s\n", state); | ||
300 | } | ||
301 | |||
302 | static ssize_t | ||
303 | lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) | ||
304 | { | ||
305 | struct Scsi_Host *host = class_to_shost(cdev); | ||
306 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; | ||
307 | struct completion online_compl; | ||
308 | int status=0; | ||
309 | |||
310 | init_completion(&online_compl); | ||
311 | |||
312 | if(strncmp(buf, "online", sizeof("online") - 1) == 0) | ||
313 | lpfc_workq_post_event(phba, &status, &online_compl, | ||
314 | LPFC_EVT_ONLINE); | ||
315 | else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) | ||
316 | lpfc_workq_post_event(phba, &status, &online_compl, | ||
317 | LPFC_EVT_OFFLINE); | ||
318 | else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) | ||
319 | lpfc_workq_post_event(phba, &status, &online_compl, | ||
320 | LPFC_EVT_WARM_START); | ||
321 | else if (strncmp(buf, "error", sizeof("error") - 1) == 0) | ||
322 | lpfc_workq_post_event(phba, &status, &online_compl, | ||
323 | LPFC_EVT_KILL); | ||
324 | else | ||
325 | return -EINVAL; | ||
326 | |||
327 | wait_for_completion(&online_compl); | ||
328 | |||
329 | if (!status) | ||
330 | return strlen(buf); | ||
331 | else | ||
332 | return -EIO; | ||
333 | } | ||
334 | |||
335 | static ssize_t | ||
282 | lpfc_poll_show(struct class_device *cdev, char *buf) | 336 | lpfc_poll_show(struct class_device *cdev, char *buf) |
283 | { | 337 | { |
284 | struct Scsi_Host *host = class_to_shost(cdev); | 338 | struct Scsi_Host *host = class_to_shost(cdev); |
@@ -480,6 +534,8 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, | |||
480 | NULL); | 534 | NULL); |
481 | static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, | 535 | static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, |
482 | lpfc_board_online_show, lpfc_board_online_store); | 536 | lpfc_board_online_show, lpfc_board_online_store); |
537 | static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, | ||
538 | lpfc_board_mode_show, lpfc_board_mode_store); | ||
483 | 539 | ||
484 | static int lpfc_poll = 0; | 540 | static int lpfc_poll = 0; |
485 | module_param(lpfc_poll, int, 0); | 541 | module_param(lpfc_poll, int, 0); |
@@ -674,6 +730,7 @@ struct class_device_attribute *lpfc_host_attrs[] = { | |||
674 | &class_device_attr_nport_evt_cnt, | 730 | &class_device_attr_nport_evt_cnt, |
675 | &class_device_attr_management_version, | 731 | &class_device_attr_management_version, |
676 | &class_device_attr_board_online, | 732 | &class_device_attr_board_online, |
733 | &class_device_attr_board_mode, | ||
677 | &class_device_attr_lpfc_poll, | 734 | &class_device_attr_lpfc_poll, |
678 | &class_device_attr_lpfc_poll_tmo, | 735 | &class_device_attr_lpfc_poll_tmo, |
679 | NULL, | 736 | NULL, |
@@ -883,8 +940,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | |||
883 | case MBX_DUMP_MEMORY: | 940 | case MBX_DUMP_MEMORY: |
884 | case MBX_DOWN_LOAD: | 941 | case MBX_DOWN_LOAD: |
885 | case MBX_UPDATE_CFG: | 942 | case MBX_UPDATE_CFG: |
943 | case MBX_KILL_BOARD: | ||
886 | case MBX_LOAD_AREA: | 944 | case MBX_LOAD_AREA: |
887 | case MBX_LOAD_EXP_ROM: | 945 | case MBX_LOAD_EXP_ROM: |
946 | case MBX_BEACON: | ||
947 | case MBX_DEL_LD_ENTRY: | ||
888 | break; | 948 | break; |
889 | case MBX_READ_SPARM64: | 949 | case MBX_READ_SPARM64: |
890 | case MBX_READ_LA: | 950 | case MBX_READ_LA: |
@@ -1042,6 +1102,8 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) | |||
1042 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; | 1102 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; |
1043 | else { | 1103 | else { |
1044 | switch (phba->hba_state) { | 1104 | switch (phba->hba_state) { |
1105 | case LPFC_STATE_UNKNOWN: | ||
1106 | case LPFC_WARM_START: | ||
1045 | case LPFC_INIT_START: | 1107 | case LPFC_INIT_START: |
1046 | case LPFC_INIT_MBX_CMDS: | 1108 | case LPFC_INIT_MBX_CMDS: |
1047 | case LPFC_LINK_DOWN: | 1109 | case LPFC_LINK_DOWN: |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 0ae49811b916..cafddf2f1af8 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -107,6 +107,7 @@ void lpfc_fdmi_tmo_handler(struct lpfc_hba *); | |||
107 | int lpfc_config_port_prep(struct lpfc_hba *); | 107 | int lpfc_config_port_prep(struct lpfc_hba *); |
108 | int lpfc_config_port_post(struct lpfc_hba *); | 108 | int lpfc_config_port_post(struct lpfc_hba *); |
109 | int lpfc_hba_down_prep(struct lpfc_hba *); | 109 | int lpfc_hba_down_prep(struct lpfc_hba *); |
110 | int lpfc_hba_down_post(struct lpfc_hba *); | ||
110 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); | 111 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); |
111 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); | 112 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); |
112 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); | 113 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); |
@@ -123,6 +124,7 @@ irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *); | |||
123 | void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); | 124 | void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); |
124 | void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); | 125 | void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); |
125 | void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); | 126 | void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); |
127 | void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||
126 | void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); | 128 | void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); |
127 | LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); | 129 | LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); |
128 | 130 | ||
@@ -135,6 +137,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); | |||
135 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); | 137 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); |
136 | void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); | 138 | void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); |
137 | uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); | 139 | uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); |
140 | |||
141 | int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); | ||
142 | int lpfc_sli_brdkill(struct lpfc_hba *); | ||
143 | int lpfc_sli_brdreset(struct lpfc_hba *); | ||
144 | int lpfc_sli_brdrestart(struct lpfc_hba *); | ||
138 | int lpfc_sli_hba_setup(struct lpfc_hba *); | 145 | int lpfc_sli_hba_setup(struct lpfc_hba *); |
139 | int lpfc_sli_hba_down(struct lpfc_hba *); | 146 | int lpfc_sli_hba_down(struct lpfc_hba *); |
140 | int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); | 147 | int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); |
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index ed6c81660e03..4dfcd4eda2fc 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -28,18 +28,24 @@ | |||
28 | * This is used by Fibre Channel protocol to support FCP. | 28 | * This is used by Fibre Channel protocol to support FCP. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /* worker thread events */ | ||
32 | enum lpfc_work_type { | ||
33 | LPFC_EVT_NODEV_TMO, | ||
34 | LPFC_EVT_ONLINE, | ||
35 | LPFC_EVT_OFFLINE, | ||
36 | LPFC_EVT_WARM_START, | ||
37 | LPFC_EVT_KILL, | ||
38 | LPFC_EVT_ELS_RETRY, | ||
39 | }; | ||
40 | |||
31 | /* structure used to queue event to the discovery tasklet */ | 41 | /* structure used to queue event to the discovery tasklet */ |
32 | struct lpfc_work_evt { | 42 | struct lpfc_work_evt { |
33 | struct list_head evt_listp; | 43 | struct list_head evt_listp; |
34 | void * evt_arg1; | 44 | void * evt_arg1; |
35 | void * evt_arg2; | 45 | void * evt_arg2; |
36 | uint32_t evt; | 46 | enum lpfc_work_type evt; |
37 | }; | 47 | }; |
38 | 48 | ||
39 | #define LPFC_EVT_NODEV_TMO 0x1 | ||
40 | #define LPFC_EVT_ONLINE 0x2 | ||
41 | #define LPFC_EVT_OFFLINE 0x3 | ||
42 | #define LPFC_EVT_ELS_RETRY 0x4 | ||
43 | 49 | ||
44 | struct lpfc_nodelist { | 50 | struct lpfc_nodelist { |
45 | struct list_head nlp_listp; | 51 | struct list_head nlp_listp; |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 5c396171ebe8..55454923029d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -120,11 +120,33 @@ lpfc_work_list_done(struct lpfc_hba * phba) | |||
120 | free_evt = 0; | 120 | free_evt = 0; |
121 | break; | 121 | break; |
122 | case LPFC_EVT_ONLINE: | 122 | case LPFC_EVT_ONLINE: |
123 | *(int *)(evtp->evt_arg1) = lpfc_online(phba); | 123 | if (phba->hba_state < LPFC_LINK_DOWN) |
124 | *(int *)(evtp->evt_arg1) = lpfc_online(phba); | ||
125 | else | ||
126 | *(int *)(evtp->evt_arg1) = 0; | ||
124 | complete((struct completion *)(evtp->evt_arg2)); | 127 | complete((struct completion *)(evtp->evt_arg2)); |
125 | break; | 128 | break; |
126 | case LPFC_EVT_OFFLINE: | 129 | case LPFC_EVT_OFFLINE: |
127 | *(int *)(evtp->evt_arg1) = lpfc_offline(phba); | 130 | if (phba->hba_state >= LPFC_LINK_DOWN) |
131 | lpfc_offline(phba); | ||
132 | lpfc_sli_brdrestart(phba); | ||
133 | *(int *)(evtp->evt_arg1) = | ||
134 | lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY); | ||
135 | complete((struct completion *)(evtp->evt_arg2)); | ||
136 | break; | ||
137 | case LPFC_EVT_WARM_START: | ||
138 | if (phba->hba_state >= LPFC_LINK_DOWN) | ||
139 | lpfc_offline(phba); | ||
140 | lpfc_sli_brdreset(phba); | ||
141 | lpfc_hba_down_post(phba); | ||
142 | *(int *)(evtp->evt_arg1) = | ||
143 | lpfc_sli_brdready(phba, HS_MBRDY); | ||
144 | complete((struct completion *)(evtp->evt_arg2)); | ||
145 | break; | ||
146 | case LPFC_EVT_KILL: | ||
147 | if (phba->hba_state >= LPFC_LINK_DOWN) | ||
148 | lpfc_offline(phba); | ||
149 | *(int *)(evtp->evt_arg1) = lpfc_sli_brdkill(phba); | ||
128 | complete((struct completion *)(evtp->evt_arg2)); | 150 | complete((struct completion *)(evtp->evt_arg2)); |
129 | break; | 151 | break; |
130 | } | 152 | } |
@@ -287,6 +309,10 @@ lpfc_linkdown(struct lpfc_hba * phba) | |||
287 | LPFC_MBOXQ_t *mb; | 309 | LPFC_MBOXQ_t *mb; |
288 | int rc, i; | 310 | int rc, i; |
289 | 311 | ||
312 | if (phba->hba_state == LPFC_LINK_DOWN) { | ||
313 | return 0; | ||
314 | } | ||
315 | |||
290 | psli = &phba->sli; | 316 | psli = &phba->sli; |
291 | 317 | ||
292 | /* sysfs or selective reset may call this routine to clean up */ | 318 | /* sysfs or selective reset may call this routine to clean up */ |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index e613dd07d2ad..98d39cea7954 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -1233,7 +1233,9 @@ typedef struct { /* FireFly BIU registers */ | |||
1233 | #define MBX_SET_MASK 0x20 | 1233 | #define MBX_SET_MASK 0x20 |
1234 | #define MBX_SET_SLIM 0x21 | 1234 | #define MBX_SET_SLIM 0x21 |
1235 | #define MBX_UNREG_D_ID 0x23 | 1235 | #define MBX_UNREG_D_ID 0x23 |
1236 | #define MBX_KILL_BOARD 0x24 | ||
1236 | #define MBX_CONFIG_FARP 0x25 | 1237 | #define MBX_CONFIG_FARP 0x25 |
1238 | #define MBX_BEACON 0x2A | ||
1237 | 1239 | ||
1238 | #define MBX_LOAD_AREA 0x81 | 1240 | #define MBX_LOAD_AREA 0x81 |
1239 | #define MBX_RUN_BIU_DIAG64 0x84 | 1241 | #define MBX_RUN_BIU_DIAG64 0x84 |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5e92c451f96e..391ca50293f2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -459,11 +459,47 @@ lpfc_hba_down_prep(struct lpfc_hba * phba) | |||
459 | lpfc_els_flush_cmd(phba); | 459 | lpfc_els_flush_cmd(phba); |
460 | lpfc_disc_flush_list(phba); | 460 | lpfc_disc_flush_list(phba); |
461 | 461 | ||
462 | /* Disable SLI2 since we disabled interrupts */ | ||
463 | phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; | ||
462 | return (0); | 464 | return (0); |
463 | } | 465 | } |
464 | 466 | ||
465 | /************************************************************************/ | 467 | /************************************************************************/ |
466 | /* */ | 468 | /* */ |
469 | /* lpfc_hba_down_post */ | ||
470 | /* This routine will do uninitialization after the HBA is reset */ | ||
471 | /* when bringing down the SLI Layer. */ | ||
472 | /* This routine returns 0 on success. Any other return value */ | ||
473 | /* indicates an error. */ | ||
474 | /* */ | ||
475 | /************************************************************************/ | ||
476 | int | ||
477 | lpfc_hba_down_post(struct lpfc_hba * phba) | ||
478 | { | ||
479 | struct lpfc_sli *psli = &phba->sli; | ||
480 | struct lpfc_sli_ring *pring; | ||
481 | struct lpfc_dmabuf *mp, *next_mp; | ||
482 | int i; | ||
483 | |||
484 | /* Cleanup preposted buffers on the ELS ring */ | ||
485 | pring = &psli->ring[LPFC_ELS_RING]; | ||
486 | list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { | ||
487 | list_del(&mp->list); | ||
488 | pring->postbufq_cnt--; | ||
489 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
490 | kfree(mp); | ||
491 | } | ||
492 | |||
493 | for (i = 0; i < psli->num_rings; i++) { | ||
494 | pring = &psli->ring[i]; | ||
495 | lpfc_sli_abort_iocb_ring(phba, pring); | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | /************************************************************************/ | ||
502 | /* */ | ||
467 | /* lpfc_handle_eratt */ | 503 | /* lpfc_handle_eratt */ |
468 | /* This routine will handle processing a Host Attention */ | 504 | /* This routine will handle processing a Host Attention */ |
469 | /* Error Status event. This will be initialized */ | 505 | /* Error Status event. This will be initialized */ |
@@ -476,20 +512,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba) | |||
476 | struct lpfc_sli *psli = &phba->sli; | 512 | struct lpfc_sli *psli = &phba->sli; |
477 | struct lpfc_sli_ring *pring; | 513 | struct lpfc_sli_ring *pring; |
478 | 514 | ||
479 | /* | ||
480 | * If a reset is sent to the HBA restore PCI configuration registers. | ||
481 | */ | ||
482 | if ( phba->hba_state == LPFC_INIT_START ) { | ||
483 | mdelay(1); | ||
484 | readl(phba->HCregaddr); /* flush */ | ||
485 | writel(0, phba->HCregaddr); | ||
486 | readl(phba->HCregaddr); /* flush */ | ||
487 | |||
488 | /* Restore PCI cmd register */ | ||
489 | pci_write_config_word(phba->pcidev, | ||
490 | PCI_COMMAND, phba->pci_cfg_value); | ||
491 | } | ||
492 | |||
493 | if (phba->work_hs & HS_FFER6) { | 515 | if (phba->work_hs & HS_FFER6) { |
494 | /* Re-establishing Link */ | 516 | /* Re-establishing Link */ |
495 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, | 517 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, |
@@ -516,6 +538,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba) | |||
516 | * attempt to restart it. | 538 | * attempt to restart it. |
517 | */ | 539 | */ |
518 | lpfc_offline(phba); | 540 | lpfc_offline(phba); |
541 | lpfc_sli_brdrestart(phba); | ||
519 | if (lpfc_online(phba) == 0) { /* Initialize the HBA */ | 542 | if (lpfc_online(phba) == 0) { /* Initialize the HBA */ |
520 | mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); | 543 | mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); |
521 | return; | 544 | return; |
@@ -532,7 +555,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba) | |||
532 | phba->work_status[0], phba->work_status[1]); | 555 | phba->work_status[0], phba->work_status[1]); |
533 | 556 | ||
534 | lpfc_offline(phba); | 557 | lpfc_offline(phba); |
535 | 558 | phba->hba_state = LPFC_HBA_ERROR; | |
559 | lpfc_hba_down_post(phba); | ||
536 | } | 560 | } |
537 | } | 561 | } |
538 | 562 | ||
@@ -1695,6 +1719,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
1695 | * the HBA. | 1719 | * the HBA. |
1696 | */ | 1720 | */ |
1697 | lpfc_sli_hba_down(phba); | 1721 | lpfc_sli_hba_down(phba); |
1722 | lpfc_sli_brdrestart(phba); | ||
1698 | 1723 | ||
1699 | /* Release the irq reservation */ | 1724 | /* Release the irq reservation */ |
1700 | free_irq(phba->pcidev->irq, phba); | 1725 | free_irq(phba->pcidev->irq, phba); |
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 6c4b21a32c7f..df88b78707de 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -637,6 +637,17 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
637 | } | 637 | } |
638 | 638 | ||
639 | void | 639 | void |
640 | lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||
641 | { | ||
642 | MAILBOX_t *mb = &pmb->mb; | ||
643 | |||
644 | memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); | ||
645 | mb->mbxCommand = MBX_KILL_BOARD; | ||
646 | mb->mbxOwner = OWN_HOST; | ||
647 | return; | ||
648 | } | ||
649 | |||
650 | void | ||
640 | lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) | 651 | lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) |
641 | { | 652 | { |
642 | struct lpfc_sli *psli; | 653 | struct lpfc_sli *psli; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1f876328b44b..d6ffe26ae123 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2005 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2006 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -513,7 +513,9 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) | |||
513 | case MBX_SET_MASK: | 513 | case MBX_SET_MASK: |
514 | case MBX_SET_SLIM: | 514 | case MBX_SET_SLIM: |
515 | case MBX_UNREG_D_ID: | 515 | case MBX_UNREG_D_ID: |
516 | case MBX_KILL_BOARD: | ||
516 | case MBX_CONFIG_FARP: | 517 | case MBX_CONFIG_FARP: |
518 | case MBX_BEACON: | ||
517 | case MBX_LOAD_AREA: | 519 | case MBX_LOAD_AREA: |
518 | case MBX_RUN_BIU_DIAG64: | 520 | case MBX_RUN_BIU_DIAG64: |
519 | case MBX_CONFIG_PORT: | 521 | case MBX_CONFIG_PORT: |
@@ -1512,98 +1514,162 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
1512 | return errcnt; | 1514 | return errcnt; |
1513 | } | 1515 | } |
1514 | 1516 | ||
1515 | /****************************************************************************** | 1517 | int |
1516 | * lpfc_sli_send_reset | 1518 | lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask) |
1517 | * | ||
1518 | * Note: After returning from this function, the HBA cannot be accessed for | ||
1519 | * 1 ms. Since we do not wish to delay in interrupt context, it is the | ||
1520 | * responsibility of the caller to perform the mdelay(1) and flush via readl(). | ||
1521 | ******************************************************************************/ | ||
1522 | static int | ||
1523 | lpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post) | ||
1524 | { | 1519 | { |
1525 | MAILBOX_t *swpmb; | 1520 | uint32_t status; |
1526 | volatile uint32_t word0; | 1521 | int i = 0; |
1527 | void __iomem *to_slim; | 1522 | int retval = 0; |
1528 | unsigned long flags = 0; | ||
1529 | 1523 | ||
1530 | spin_lock_irqsave(phba->host->host_lock, flags); | 1524 | /* Read the HBA Host Status Register */ |
1525 | status = readl(phba->HSregaddr); | ||
1531 | 1526 | ||
1532 | /* A board reset must use REAL SLIM. */ | 1527 | /* |
1533 | phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; | 1528 | * Check status register every 100ms for 5 retries, then every |
1529 | * 500ms for 5, then every 2.5 sec for 5, then reset board and | ||
1530 | * every 2.5 sec for 4. | ||
1531 | * Break our of the loop if errors occurred during init. | ||
1532 | */ | ||
1533 | while (((status & mask) != mask) && | ||
1534 | !(status & HS_FFERM) && | ||
1535 | i++ < 20) { | ||
1534 | 1536 | ||
1535 | word0 = 0; | 1537 | if (i <= 5) |
1536 | swpmb = (MAILBOX_t *) & word0; | 1538 | msleep(10); |
1537 | swpmb->mbxCommand = MBX_RESTART; | 1539 | else if (i <= 10) |
1538 | swpmb->mbxHc = 1; | 1540 | msleep(500); |
1541 | else | ||
1542 | msleep(2500); | ||
1539 | 1543 | ||
1540 | to_slim = phba->MBslimaddr; | 1544 | if (i == 15) { |
1541 | writel(*(uint32_t *) swpmb, to_slim); | 1545 | phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */ |
1542 | readl(to_slim); /* flush */ | 1546 | lpfc_sli_brdrestart(phba); |
1547 | } | ||
1548 | /* Read the HBA Host Status Register */ | ||
1549 | status = readl(phba->HSregaddr); | ||
1550 | } | ||
1543 | 1551 | ||
1544 | /* Only skip post after fc_ffinit is completed */ | 1552 | /* Check to see if any errors occurred during init */ |
1545 | if (skip_post) { | 1553 | if ((status & HS_FFERM) || (i >= 20)) { |
1546 | word0 = 1; /* This is really setting up word1 */ | 1554 | phba->hba_state = LPFC_HBA_ERROR; |
1547 | } else { | 1555 | retval = 1; |
1548 | word0 = 0; /* This is really setting up word1 */ | ||
1549 | } | 1556 | } |
1550 | to_slim = phba->MBslimaddr + sizeof (uint32_t); | ||
1551 | writel(*(uint32_t *) swpmb, to_slim); | ||
1552 | readl(to_slim); /* flush */ | ||
1553 | 1557 | ||
1554 | /* Turn off parity checking and serr during the physical reset */ | 1558 | return retval; |
1555 | pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value); | 1559 | } |
1556 | pci_write_config_word(phba->pcidev, PCI_COMMAND, | ||
1557 | (phba->pci_cfg_value & | ||
1558 | ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); | ||
1559 | 1560 | ||
1560 | writel(HC_INITFF, phba->HCregaddr); | 1561 | int |
1562 | lpfc_sli_brdkill(struct lpfc_hba * phba) | ||
1563 | { | ||
1564 | struct lpfc_sli *psli; | ||
1565 | LPFC_MBOXQ_t *pmb; | ||
1566 | uint32_t status; | ||
1567 | uint32_t ha_copy; | ||
1568 | int retval; | ||
1569 | int i = 0; | ||
1561 | 1570 | ||
1562 | phba->hba_state = LPFC_INIT_START; | 1571 | psli = &phba->sli; |
1563 | spin_unlock_irqrestore(phba->host->host_lock, flags); | ||
1564 | 1572 | ||
1565 | return 0; | 1573 | /* Kill HBA */ |
1574 | lpfc_printf_log(phba, | ||
1575 | KERN_INFO, | ||
1576 | LOG_SLI, | ||
1577 | "%d:0329 Kill HBA Data: x%x x%x\n", | ||
1578 | phba->brd_no, | ||
1579 | phba->hba_state, | ||
1580 | psli->sli_flag); | ||
1581 | |||
1582 | if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, | ||
1583 | GFP_ATOMIC)) == 0) { | ||
1584 | return 1; | ||
1585 | } | ||
1586 | |||
1587 | /* Disable the error attention */ | ||
1588 | spin_lock_irq(phba->host->host_lock); | ||
1589 | status = readl(phba->HCregaddr); | ||
1590 | status &= ~HC_ERINT_ENA; | ||
1591 | writel(status, phba->HCregaddr); | ||
1592 | readl(phba->HCregaddr); /* flush */ | ||
1593 | spin_unlock_irq(phba->host->host_lock); | ||
1594 | |||
1595 | lpfc_kill_board(phba, pmb); | ||
1596 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
1597 | retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); | ||
1598 | |||
1599 | if (retval != MBX_SUCCESS) { | ||
1600 | if (retval != MBX_BUSY) | ||
1601 | mempool_free(pmb, phba->mbox_mem_pool); | ||
1602 | return 1; | ||
1603 | } | ||
1604 | |||
1605 | mempool_free(pmb, phba->mbox_mem_pool); | ||
1606 | |||
1607 | /* There is no completion for a KILL_BOARD mbox cmd. Check for an error | ||
1608 | * attention every 100ms for 3 seconds. If we don't get ERATT after | ||
1609 | * 3 seconds we still set HBA_ERROR state because the status of the | ||
1610 | * board is now undefined. | ||
1611 | */ | ||
1612 | ha_copy = readl(phba->HAregaddr); | ||
1613 | |||
1614 | while ((i++ < 30) && !(ha_copy & HA_ERATT)) { | ||
1615 | mdelay(100); | ||
1616 | ha_copy = readl(phba->HAregaddr); | ||
1617 | } | ||
1618 | |||
1619 | del_timer_sync(&psli->mbox_tmo); | ||
1620 | |||
1621 | spin_lock_irq(phba->host->host_lock); | ||
1622 | psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; | ||
1623 | spin_unlock_irq(phba->host->host_lock); | ||
1624 | |||
1625 | psli->mbox_active = NULL; | ||
1626 | lpfc_hba_down_post(phba); | ||
1627 | phba->hba_state = LPFC_HBA_ERROR; | ||
1628 | |||
1629 | return (ha_copy & HA_ERATT ? 0 : 1); | ||
1566 | } | 1630 | } |
1567 | 1631 | ||
1568 | static int | 1632 | int |
1569 | lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post) | 1633 | lpfc_sli_brdreset(struct lpfc_hba * phba) |
1570 | { | 1634 | { |
1635 | struct lpfc_sli *psli; | ||
1571 | struct lpfc_sli_ring *pring; | 1636 | struct lpfc_sli_ring *pring; |
1637 | uint16_t cfg_value; | ||
1572 | int i; | 1638 | int i; |
1573 | struct lpfc_dmabuf *mp, *next_mp; | ||
1574 | unsigned long flags = 0; | ||
1575 | |||
1576 | lpfc_sli_send_reset(phba, skip_post); | ||
1577 | mdelay(1); | ||
1578 | 1639 | ||
1579 | spin_lock_irqsave(phba->host->host_lock, flags); | 1640 | psli = &phba->sli; |
1580 | /* Risk the write on flush case ie no delay after the readl */ | ||
1581 | readl(phba->HCregaddr); /* flush */ | ||
1582 | /* Now toggle INITFF bit set by lpfc_sli_send_reset */ | ||
1583 | writel(0, phba->HCregaddr); | ||
1584 | readl(phba->HCregaddr); /* flush */ | ||
1585 | 1641 | ||
1586 | /* Restore PCI cmd register */ | 1642 | /* Reset HBA */ |
1587 | pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value); | 1643 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, |
1644 | "%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no, | ||
1645 | phba->hba_state, psli->sli_flag); | ||
1588 | 1646 | ||
1589 | /* perform board reset */ | 1647 | /* perform board reset */ |
1590 | phba->fc_eventTag = 0; | 1648 | phba->fc_eventTag = 0; |
1591 | phba->fc_myDID = 0; | 1649 | phba->fc_myDID = 0; |
1592 | phba->fc_prevDID = Mask_DID; | 1650 | phba->fc_prevDID = 0; |
1593 | 1651 | ||
1594 | /* Reset HBA */ | 1652 | psli->sli_flag = 0; |
1595 | lpfc_printf_log(phba, | 1653 | |
1596 | KERN_INFO, | 1654 | /* Turn off parity checking and serr during the physical reset */ |
1597 | LOG_SLI, | 1655 | pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); |
1598 | "%d:0325 Reset HBA Data: x%x x%x x%x\n", | 1656 | pci_write_config_word(phba->pcidev, PCI_COMMAND, |
1599 | phba->brd_no, | 1657 | (cfg_value & |
1600 | phba->hba_state, | 1658 | ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); |
1601 | phba->sli.sli_flag, | 1659 | |
1602 | skip_post); | 1660 | /* Now toggle INITFF bit in the Host Control Register */ |
1661 | writel(HC_INITFF, phba->HCregaddr); | ||
1662 | mdelay(1); | ||
1663 | readl(phba->HCregaddr); /* flush */ | ||
1664 | writel(0, phba->HCregaddr); | ||
1665 | readl(phba->HCregaddr); /* flush */ | ||
1666 | |||
1667 | /* Restore PCI cmd register */ | ||
1668 | pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); | ||
1603 | 1669 | ||
1604 | /* Initialize relevant SLI info */ | 1670 | /* Initialize relevant SLI info */ |
1605 | for (i = 0; i < phba->sli.num_rings; i++) { | 1671 | for (i = 0; i < psli->num_rings; i++) { |
1606 | pring = &phba->sli.ring[i]; | 1672 | pring = &psli->ring[i]; |
1607 | pring->flag = 0; | 1673 | pring->flag = 0; |
1608 | pring->rspidx = 0; | 1674 | pring->rspidx = 0; |
1609 | pring->next_cmdidx = 0; | 1675 | pring->next_cmdidx = 0; |
@@ -1611,27 +1677,62 @@ lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post) | |||
1611 | pring->cmdidx = 0; | 1677 | pring->cmdidx = 0; |
1612 | pring->missbufcnt = 0; | 1678 | pring->missbufcnt = 0; |
1613 | } | 1679 | } |
1614 | spin_unlock_irqrestore(phba->host->host_lock, flags); | ||
1615 | 1680 | ||
1616 | if (skip_post) { | 1681 | phba->hba_state = LPFC_WARM_START; |
1617 | mdelay(100); | 1682 | return 0; |
1683 | } | ||
1684 | |||
1685 | int | ||
1686 | lpfc_sli_brdrestart(struct lpfc_hba * phba) | ||
1687 | { | ||
1688 | MAILBOX_t *mb; | ||
1689 | struct lpfc_sli *psli; | ||
1690 | uint16_t skip_post; | ||
1691 | volatile uint32_t word0; | ||
1692 | void __iomem *to_slim; | ||
1693 | |||
1694 | spin_lock_irq(phba->host->host_lock); | ||
1695 | |||
1696 | psli = &phba->sli; | ||
1697 | |||
1698 | /* Restart HBA */ | ||
1699 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||
1700 | "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no, | ||
1701 | phba->hba_state, psli->sli_flag); | ||
1702 | |||
1703 | word0 = 0; | ||
1704 | mb = (MAILBOX_t *) &word0; | ||
1705 | mb->mbxCommand = MBX_RESTART; | ||
1706 | mb->mbxHc = 1; | ||
1707 | |||
1708 | to_slim = phba->MBslimaddr; | ||
1709 | writel(*(uint32_t *) mb, to_slim); | ||
1710 | readl(to_slim); /* flush */ | ||
1711 | |||
1712 | /* Only skip post after fc_ffinit is completed */ | ||
1713 | if (phba->hba_state) { | ||
1714 | skip_post = 1; | ||
1715 | word0 = 1; /* This is really setting up word1 */ | ||
1618 | } else { | 1716 | } else { |
1619 | mdelay(2000); | 1717 | skip_post = 0; |
1718 | word0 = 0; /* This is really setting up word1 */ | ||
1620 | } | 1719 | } |
1720 | to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t); | ||
1721 | writel(*(uint32_t *) mb, to_slim); | ||
1722 | readl(to_slim); /* flush */ | ||
1621 | 1723 | ||
1622 | spin_lock_irqsave(phba->host->host_lock, flags); | 1724 | lpfc_sli_brdreset(phba); |
1623 | /* Cleanup preposted buffers on the ELS ring */ | ||
1624 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
1625 | list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { | ||
1626 | list_del(&mp->list); | ||
1627 | pring->postbufq_cnt--; | ||
1628 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
1629 | kfree(mp); | ||
1630 | } | ||
1631 | spin_unlock_irqrestore(phba->host->host_lock, flags); | ||
1632 | 1725 | ||
1633 | for (i = 0; i < phba->sli.num_rings; i++) | 1726 | phba->hba_state = LPFC_INIT_START; |
1634 | lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]); | 1727 | |
1728 | spin_unlock_irq(phba->host->host_lock); | ||
1729 | |||
1730 | if (skip_post) | ||
1731 | mdelay(100); | ||
1732 | else | ||
1733 | mdelay(2000); | ||
1734 | |||
1735 | lpfc_hba_down_post(phba); | ||
1635 | 1736 | ||
1636 | return 0; | 1737 | return 0; |
1637 | } | 1738 | } |
@@ -1691,7 +1792,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) | |||
1691 | } | 1792 | } |
1692 | 1793 | ||
1693 | if (i == 15) { | 1794 | if (i == 15) { |
1694 | lpfc_sli_brdreset(phba, 0); | 1795 | phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */ |
1796 | lpfc_sli_brdrestart(phba); | ||
1695 | } | 1797 | } |
1696 | /* Read the HBA Host Status Register */ | 1798 | /* Read the HBA Host Status Register */ |
1697 | status = readl(phba->HSregaddr); | 1799 | status = readl(phba->HSregaddr); |
@@ -1735,8 +1837,8 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) | |||
1735 | } | 1837 | } |
1736 | 1838 | ||
1737 | while (resetcount < 2 && !done) { | 1839 | while (resetcount < 2 && !done) { |
1738 | phba->hba_state = 0; | 1840 | phba->hba_state = LPFC_STATE_UNKNOWN; |
1739 | lpfc_sli_brdreset(phba, 0); | 1841 | lpfc_sli_brdrestart(phba); |
1740 | msleep(2500); | 1842 | msleep(2500); |
1741 | rc = lpfc_sli_chipset_init(phba); | 1843 | rc = lpfc_sli_chipset_init(phba); |
1742 | if (rc) | 1844 | if (rc) |
@@ -1920,6 +2022,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) | |||
1920 | mb = &pmbox->mb; | 2022 | mb = &pmbox->mb; |
1921 | status = MBX_SUCCESS; | 2023 | status = MBX_SUCCESS; |
1922 | 2024 | ||
2025 | if (phba->hba_state == LPFC_HBA_ERROR) { | ||
2026 | spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); | ||
2027 | |||
2028 | /* Mbox command <mbxCommand> cannot issue */ | ||
2029 | LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) | ||
2030 | return (MBX_NOT_FINISHED); | ||
2031 | } | ||
2032 | |||
1923 | if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { | 2033 | if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { |
1924 | /* Polling for a mbox command when another one is already active | 2034 | /* Polling for a mbox command when another one is already active |
1925 | * is not allowed in SLI. Also, the driver must have established | 2035 | * 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) | |||
2002 | 2112 | ||
2003 | /* If we are not polling, we MUST be in SLI2 mode */ | 2113 | /* If we are not polling, we MUST be in SLI2 mode */ |
2004 | if (flag != MBX_POLL) { | 2114 | if (flag != MBX_POLL) { |
2005 | if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { | 2115 | if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) && |
2116 | (mb->mbxCommand != MBX_KILL_BOARD)) { | ||
2006 | psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; | 2117 | psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; |
2007 | spin_unlock_irqrestore(phba->host->host_lock, | 2118 | spin_unlock_irqrestore(phba->host->host_lock, |
2008 | drvr_flag); | 2119 | drvr_flag); |
@@ -2035,7 +2146,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) | |||
2035 | /* First copy command data to host SLIM area */ | 2146 | /* First copy command data to host SLIM area */ |
2036 | lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); | 2147 | lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); |
2037 | } else { | 2148 | } else { |
2038 | if (mb->mbxCommand == MBX_CONFIG_PORT) { | 2149 | if (mb->mbxCommand == MBX_CONFIG_PORT || |
2150 | mb->mbxCommand == MBX_KILL_BOARD) { | ||
2039 | /* copy command data into host mbox for cmpl */ | 2151 | /* copy command data into host mbox for cmpl */ |
2040 | lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, | 2152 | lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, |
2041 | MAILBOX_CMD_SIZE); | 2153 | MAILBOX_CMD_SIZE); |
@@ -2086,8 +2198,9 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) | |||
2086 | ha_copy = readl(phba->HAregaddr); | 2198 | ha_copy = readl(phba->HAregaddr); |
2087 | 2199 | ||
2088 | /* Wait for command to complete */ | 2200 | /* Wait for command to complete */ |
2089 | while (((word0 & OWN_CHIP) == OWN_CHIP) | 2201 | while (((word0 & OWN_CHIP) == OWN_CHIP) || |
2090 | || !(ha_copy & HA_MBATT)) { | 2202 | (!(ha_copy & HA_MBATT) && |
2203 | (phba->hba_state > LPFC_WARM_START))) { | ||
2091 | if (i++ >= 100) { | 2204 | if (i++ >= 100) { |
2092 | psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; | 2205 | psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; |
2093 | spin_unlock_irqrestore(phba->host->host_lock, | 2206 | spin_unlock_irqrestore(phba->host->host_lock, |
@@ -2455,15 +2568,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) | |||
2455 | 2568 | ||
2456 | spin_unlock_irqrestore(phba->host->host_lock, flags); | 2569 | spin_unlock_irqrestore(phba->host->host_lock, flags); |
2457 | 2570 | ||
2458 | /* | ||
2459 | * Provided the hba is not in an error state, reset it. It is not | ||
2460 | * capable of IO anymore. | ||
2461 | */ | ||
2462 | if (phba->hba_state != LPFC_HBA_ERROR) { | ||
2463 | phba->hba_state = LPFC_INIT_START; | ||
2464 | lpfc_sli_brdreset(phba, 1); | ||
2465 | } | ||
2466 | |||
2467 | return 1; | 2571 | return 1; |
2468 | } | 2572 | } |
2469 | 2573 | ||
@@ -2976,13 +3080,6 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) | |||
2976 | /* Clear Chip error bit */ | 3080 | /* Clear Chip error bit */ |
2977 | writel(HA_ERATT, phba->HAregaddr); | 3081 | writel(HA_ERATT, phba->HAregaddr); |
2978 | readl(phba->HAregaddr); /* flush */ | 3082 | readl(phba->HAregaddr); /* flush */ |
2979 | |||
2980 | /* | ||
2981 | * Reseting the HBA is the only reliable way | ||
2982 | * to shutdown interrupt when there is a | ||
2983 | * ERROR. | ||
2984 | */ | ||
2985 | lpfc_sli_send_reset(phba, 1); | ||
2986 | } | 3083 | } |
2987 | 3084 | ||
2988 | spin_lock(phba->host->host_lock); | 3085 | spin_lock(phba->host->host_lock); |