diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-08-24 21:50:30 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-13 09:28:55 -0400 |
commit | 9399627f340794baebf7e4581470ccb92f019acc (patch) | |
tree | c30e656a1c353e2f025bb5ca3daf142128434a34 | |
parent | 0f1f53a7efd60d7cdd8e82925f0c62dcf64ba092 (diff) |
[SCSI] lpfc 8.2.8 : Add MSI-X support
Add support for MSI-X Multi-Message interrupts. We use different vectors
for fast-path interrupts (i/o) and slow-patch interrupts (discovery, etc).
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 35 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 43 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 63 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 230 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 80 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 401 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 4 |
9 files changed, 699 insertions, 167 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index aee5444b63d9..181538466117 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -49,6 +49,9 @@ struct lpfc_sli2_slim; | |||
49 | #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ | 49 | #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ |
50 | #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ | 50 | #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ |
51 | 51 | ||
52 | /* Error Attention event polling interval */ | ||
53 | #define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ | ||
54 | |||
52 | /* Define macros for 64 bit support */ | 55 | /* Define macros for 64 bit support */ |
53 | #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) | 56 | #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) |
54 | #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) | 57 | #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) |
@@ -60,6 +63,9 @@ struct lpfc_sli2_slim; | |||
60 | 63 | ||
61 | #define MAX_HBAEVT 32 | 64 | #define MAX_HBAEVT 32 |
62 | 65 | ||
66 | /* Number of MSI-X vectors the driver uses */ | ||
67 | #define LPFC_MSIX_VECTORS 2 | ||
68 | |||
63 | /* lpfc wait event data ready flag */ | 69 | /* lpfc wait event data ready flag */ |
64 | #define LPFC_DATA_READY (1<<0) | 70 | #define LPFC_DATA_READY (1<<0) |
65 | 71 | ||
@@ -423,12 +429,16 @@ struct lpfc_hba { | |||
423 | #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ | 429 | #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ |
424 | #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ | 430 | #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ |
425 | 431 | ||
432 | uint32_t hba_flag; /* hba generic flags */ | ||
433 | #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ | ||
434 | |||
426 | struct lpfc_dmabuf slim2p; | 435 | struct lpfc_dmabuf slim2p; |
427 | 436 | ||
428 | MAILBOX_t *mbox; | 437 | MAILBOX_t *mbox; |
429 | uint32_t *inb_ha_copy; | 438 | uint32_t *inb_ha_copy; |
430 | uint32_t *inb_counter; | 439 | uint32_t *inb_counter; |
431 | uint32_t inb_last_counter; | 440 | uint32_t inb_last_counter; |
441 | uint32_t ha_copy; | ||
432 | struct _PCB *pcb; | 442 | struct _PCB *pcb; |
433 | struct _IOCB *IOCBs; | 443 | struct _IOCB *IOCBs; |
434 | 444 | ||
@@ -544,6 +554,7 @@ struct lpfc_hba { | |||
544 | uint8_t soft_wwn_enable; | 554 | uint8_t soft_wwn_enable; |
545 | 555 | ||
546 | struct timer_list fcp_poll_timer; | 556 | struct timer_list fcp_poll_timer; |
557 | struct timer_list eratt_poll; | ||
547 | 558 | ||
548 | /* | 559 | /* |
549 | * stat counters | 560 | * stat counters |
@@ -573,7 +584,7 @@ struct lpfc_hba { | |||
573 | 584 | ||
574 | struct fc_host_statistics link_stats; | 585 | struct fc_host_statistics link_stats; |
575 | enum intr_type_t intr_type; | 586 | enum intr_type_t intr_type; |
576 | struct msix_entry msix_entries[1]; | 587 | struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; |
577 | 588 | ||
578 | struct list_head port_list; | 589 | struct list_head port_list; |
579 | struct lpfc_vport *pport; /* physical lpfc_vport pointer */ | 590 | struct lpfc_vport *pport; /* physical lpfc_vport pointer */ |
@@ -660,6 +671,28 @@ lpfc_worker_wake_up(struct lpfc_hba *phba) | |||
660 | return; | 671 | return; |
661 | } | 672 | } |
662 | 673 | ||
674 | static inline void | ||
675 | lpfc_sli_read_hs(struct lpfc_hba *phba) | ||
676 | { | ||
677 | /* | ||
678 | * There was a link/board error. Read the status register to retrieve | ||
679 | * the error event and process it. | ||
680 | */ | ||
681 | phba->sli.slistat.err_attn_event++; | ||
682 | |||
683 | /* Save status info */ | ||
684 | phba->work_hs = readl(phba->HSregaddr); | ||
685 | phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); | ||
686 | phba->work_status[1] = readl(phba->MBslimaddr + 0xac); | ||
687 | |||
688 | /* Clear chip Host Attention error bit */ | ||
689 | writel(HA_ERATT, phba->HAregaddr); | ||
690 | readl(phba->HAregaddr); /* flush */ | ||
691 | phba->pport->stopped = 1; | ||
692 | |||
693 | return; | ||
694 | } | ||
695 | |||
663 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ | 696 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ |
664 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature | 697 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature |
665 | event */ | 698 | event */ |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b9acc6eefe62..21397f37010d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -2372,12 +2372,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, | |||
2372 | /* | 2372 | /* |
2373 | # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that | 2373 | # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that |
2374 | # support this feature | 2374 | # support this feature |
2375 | # 0 = MSI disabled (default) | 2375 | # 0 = MSI disabled |
2376 | # 1 = MSI enabled | 2376 | # 1 = MSI enabled |
2377 | # 2 = MSI-X enabled | 2377 | # 2 = MSI-X enabled (default) |
2378 | # Value range is [0,2]. Default value is 0. | 2378 | # Value range is [0,2]. Default value is 2. |
2379 | */ | 2379 | */ |
2380 | LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " | 2380 | LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " |
2381 | "MSI-X (2), if possible"); | 2381 | "MSI-X (2), if possible"); |
2382 | 2382 | ||
2383 | /* | 2383 | /* |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 495afd06936b..7d173f4a37f5 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -18,7 +18,7 @@ | |||
18 | * included with this package. * | 18 | * included with this package. * |
19 | *******************************************************************/ | 19 | *******************************************************************/ |
20 | 20 | ||
21 | typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param); | 21 | typedef int (*node_filter)(struct lpfc_nodelist *, void *); |
22 | 22 | ||
23 | struct fc_rport; | 23 | struct fc_rport; |
24 | void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); | 24 | void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); |
@@ -26,11 +26,11 @@ void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); | |||
26 | void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); | 26 | void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); |
27 | 27 | ||
28 | void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); | 28 | void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); |
29 | int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, | 29 | int lpfc_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *); |
30 | struct lpfc_dmabuf *mp); | ||
31 | void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | 30 | void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); |
32 | void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport); | 31 | void lpfc_issue_clear_la(struct lpfc_hba *, struct lpfc_vport *); |
33 | void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); | 32 | void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); |
33 | int lpfc_config_msi(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||
34 | int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); | 34 | int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); |
35 | void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); | 35 | void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); |
36 | void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); | 36 | void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); |
@@ -43,7 +43,7 @@ void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); | |||
43 | void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); | 43 | void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); |
44 | 44 | ||
45 | struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); | 45 | struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); |
46 | void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); | 46 | void lpfc_cleanup_rpis(struct lpfc_vport *, int); |
47 | int lpfc_linkdown(struct lpfc_hba *); | 47 | int lpfc_linkdown(struct lpfc_hba *); |
48 | void lpfc_port_link_failure(struct lpfc_vport *); | 48 | void lpfc_port_link_failure(struct lpfc_vport *); |
49 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | 49 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); |
@@ -135,7 +135,7 @@ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, | |||
135 | int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); | 135 | int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); |
136 | int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); | 136 | int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); |
137 | void lpfc_fdmi_tmo(unsigned long); | 137 | void lpfc_fdmi_tmo(unsigned long); |
138 | void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport); | 138 | void lpfc_fdmi_timeout_handler(struct lpfc_vport *); |
139 | 139 | ||
140 | int lpfc_config_port_prep(struct lpfc_hba *); | 140 | int lpfc_config_port_prep(struct lpfc_hba *); |
141 | int lpfc_config_port_post(struct lpfc_hba *); | 141 | int lpfc_config_port_post(struct lpfc_hba *); |
@@ -155,6 +155,8 @@ int lpfc_sli_queue_setup(struct lpfc_hba *); | |||
155 | void lpfc_handle_eratt(struct lpfc_hba *); | 155 | void lpfc_handle_eratt(struct lpfc_hba *); |
156 | void lpfc_handle_latt(struct lpfc_hba *); | 156 | void lpfc_handle_latt(struct lpfc_hba *); |
157 | irqreturn_t lpfc_intr_handler(int, void *); | 157 | irqreturn_t lpfc_intr_handler(int, void *); |
158 | irqreturn_t lpfc_sp_intr_handler(int, void *); | ||
159 | irqreturn_t lpfc_fp_intr_handler(int, void *); | ||
158 | 160 | ||
159 | void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); | 161 | void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); |
160 | void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); | 162 | void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); |
@@ -175,11 +177,12 @@ void lpfc_mem_free(struct lpfc_hba *); | |||
175 | void lpfc_stop_vport_timers(struct lpfc_vport *); | 177 | void lpfc_stop_vport_timers(struct lpfc_vport *); |
176 | 178 | ||
177 | void lpfc_poll_timeout(unsigned long ptr); | 179 | void lpfc_poll_timeout(unsigned long ptr); |
178 | void lpfc_poll_start_timer(struct lpfc_hba * phba); | 180 | void lpfc_poll_start_timer(struct lpfc_hba *); |
179 | void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); | 181 | void lpfc_poll_eratt(unsigned long); |
182 | void lpfc_sli_poll_fcp_ring(struct lpfc_hba *); | ||
180 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); | 183 | struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); |
181 | void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); | 184 | void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); |
182 | uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); | 185 | uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); |
183 | 186 | ||
184 | void lpfc_reset_barrier(struct lpfc_hba * phba); | 187 | void lpfc_reset_barrier(struct lpfc_hba * phba); |
185 | int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); | 188 | int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); |
@@ -187,11 +190,13 @@ int lpfc_sli_brdkill(struct lpfc_hba *); | |||
187 | int lpfc_sli_brdreset(struct lpfc_hba *); | 190 | int lpfc_sli_brdreset(struct lpfc_hba *); |
188 | int lpfc_sli_brdrestart(struct lpfc_hba *); | 191 | int lpfc_sli_brdrestart(struct lpfc_hba *); |
189 | int lpfc_sli_hba_setup(struct lpfc_hba *); | 192 | int lpfc_sli_hba_setup(struct lpfc_hba *); |
193 | int lpfc_sli_config_port(struct lpfc_hba *, int); | ||
190 | int lpfc_sli_host_down(struct lpfc_vport *); | 194 | int lpfc_sli_host_down(struct lpfc_vport *); |
191 | int lpfc_sli_hba_down(struct lpfc_hba *); | 195 | int lpfc_sli_hba_down(struct lpfc_hba *); |
192 | int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); | 196 | int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); |
193 | int lpfc_sli_handle_mb_event(struct lpfc_hba *); | 197 | int lpfc_sli_handle_mb_event(struct lpfc_hba *); |
194 | int lpfc_sli_flush_mbox_queue(struct lpfc_hba *); | 198 | int lpfc_sli_flush_mbox_queue(struct lpfc_hba *); |
199 | int lpfc_sli_check_eratt(struct lpfc_hba *); | ||
195 | int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, | 200 | int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, |
196 | struct lpfc_sli_ring *, uint32_t); | 201 | struct lpfc_sli_ring *, uint32_t); |
197 | void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); | 202 | void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); |
@@ -227,17 +232,13 @@ struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); | |||
227 | struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, | 232 | struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, |
228 | struct lpfc_name *); | 233 | struct lpfc_name *); |
229 | 234 | ||
230 | int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, | 235 | int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); |
231 | uint32_t timeout); | 236 | |
232 | 237 | int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, struct lpfc_sli_ring *, | |
233 | int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, | 238 | struct lpfc_iocbq *, struct lpfc_iocbq *, |
234 | struct lpfc_sli_ring * pring, | 239 | uint32_t); |
235 | struct lpfc_iocbq * piocb, | 240 | void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *, |
236 | struct lpfc_iocbq * prspiocbq, | 241 | struct lpfc_iocbq *); |
237 | uint32_t timeout); | ||
238 | void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, | ||
239 | struct lpfc_iocbq * cmdiocb, | ||
240 | struct lpfc_iocbq * rspiocb); | ||
241 | 242 | ||
242 | void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); | 243 | void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); |
243 | 244 | ||
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 897ef7d7a8e9..3b00d9b86c7b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -369,6 +369,7 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
369 | spin_unlock_irq(&phba->hbalock); | 369 | spin_unlock_irq(&phba->hbalock); |
370 | 370 | ||
371 | if (ha_copy & HA_ERATT) | 371 | if (ha_copy & HA_ERATT) |
372 | /* Handle the error attention event */ | ||
372 | lpfc_handle_eratt(phba); | 373 | lpfc_handle_eratt(phba); |
373 | 374 | ||
374 | if (ha_copy & HA_MBATT) | 375 | if (ha_copy & HA_MBATT) |
@@ -376,6 +377,7 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
376 | 377 | ||
377 | if (ha_copy & HA_LATT) | 378 | if (ha_copy & HA_LATT) |
378 | lpfc_handle_latt(phba); | 379 | lpfc_handle_latt(phba); |
380 | |||
379 | vports = lpfc_create_vport_work_array(phba); | 381 | vports = lpfc_create_vport_work_array(phba); |
380 | if (vports != NULL) | 382 | if (vports != NULL) |
381 | for(i = 0; i <= phba->max_vpi; i++) { | 383 | for(i = 0; i <= phba->max_vpi; i++) { |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index ee4e50175ca8..5de5dabbbee6 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -1203,6 +1203,18 @@ typedef struct { /* FireFly BIU registers */ | |||
1203 | #define HA_RXATT 0x00000008 /* Bit 3 */ | 1203 | #define HA_RXATT 0x00000008 /* Bit 3 */ |
1204 | #define HA_RXMASK 0x0000000f | 1204 | #define HA_RXMASK 0x0000000f |
1205 | 1205 | ||
1206 | #define HA_R0_CLR_MSK (HA_R0RE_REQ | HA_R0CE_RSP | HA_R0ATT) | ||
1207 | #define HA_R1_CLR_MSK (HA_R1RE_REQ | HA_R1CE_RSP | HA_R1ATT) | ||
1208 | #define HA_R2_CLR_MSK (HA_R2RE_REQ | HA_R2CE_RSP | HA_R2ATT) | ||
1209 | #define HA_R3_CLR_MSK (HA_R3RE_REQ | HA_R3CE_RSP | HA_R3ATT) | ||
1210 | |||
1211 | #define HA_R0_POS 3 | ||
1212 | #define HA_R1_POS 7 | ||
1213 | #define HA_R2_POS 11 | ||
1214 | #define HA_R3_POS 15 | ||
1215 | #define HA_LE_POS 29 | ||
1216 | #define HA_MB_POS 30 | ||
1217 | #define HA_ER_POS 31 | ||
1206 | /* Chip Attention Register */ | 1218 | /* Chip Attention Register */ |
1207 | 1219 | ||
1208 | #define CA_REG_OFFSET 4 /* Byte offset from register base address */ | 1220 | #define CA_REG_OFFSET 4 /* Byte offset from register base address */ |
@@ -1240,7 +1252,7 @@ typedef struct { /* FireFly BIU registers */ | |||
1240 | 1252 | ||
1241 | /* Host Control Register */ | 1253 | /* Host Control Register */ |
1242 | 1254 | ||
1243 | #define HC_REG_OFFSET 12 /* Word offset from register base address */ | 1255 | #define HC_REG_OFFSET 12 /* Byte offset from register base address */ |
1244 | 1256 | ||
1245 | #define HC_MBINT_ENA 0x00000001 /* Bit 0 */ | 1257 | #define HC_MBINT_ENA 0x00000001 /* Bit 0 */ |
1246 | #define HC_R0INT_ENA 0x00000002 /* Bit 1 */ | 1258 | #define HC_R0INT_ENA 0x00000002 /* Bit 1 */ |
@@ -1253,6 +1265,19 @@ typedef struct { /* FireFly BIU registers */ | |||
1253 | #define HC_LAINT_ENA 0x20000000 /* Bit 29 */ | 1265 | #define HC_LAINT_ENA 0x20000000 /* Bit 29 */ |
1254 | #define HC_ERINT_ENA 0x80000000 /* Bit 31 */ | 1266 | #define HC_ERINT_ENA 0x80000000 /* Bit 31 */ |
1255 | 1267 | ||
1268 | /* Message Signaled Interrupt eXtension (MSI-X) message identifiers */ | ||
1269 | #define MSIX_DFLT_ID 0 | ||
1270 | #define MSIX_RNG0_ID 0 | ||
1271 | #define MSIX_RNG1_ID 1 | ||
1272 | #define MSIX_RNG2_ID 2 | ||
1273 | #define MSIX_RNG3_ID 3 | ||
1274 | |||
1275 | #define MSIX_LINK_ID 4 | ||
1276 | #define MSIX_MBOX_ID 5 | ||
1277 | |||
1278 | #define MSIX_SPARE0_ID 6 | ||
1279 | #define MSIX_SPARE1_ID 7 | ||
1280 | |||
1256 | /* Mailbox Commands */ | 1281 | /* Mailbox Commands */ |
1257 | #define MBX_SHUTDOWN 0x00 /* terminate testing */ | 1282 | #define MBX_SHUTDOWN 0x00 /* terminate testing */ |
1258 | #define MBX_LOAD_SM 0x01 | 1283 | #define MBX_LOAD_SM 0x01 |
@@ -1290,6 +1315,7 @@ typedef struct { /* FireFly BIU registers */ | |||
1290 | #define MBX_KILL_BOARD 0x24 | 1315 | #define MBX_KILL_BOARD 0x24 |
1291 | #define MBX_CONFIG_FARP 0x25 | 1316 | #define MBX_CONFIG_FARP 0x25 |
1292 | #define MBX_BEACON 0x2A | 1317 | #define MBX_BEACON 0x2A |
1318 | #define MBX_CONFIG_MSI 0x30 | ||
1293 | #define MBX_HEARTBEAT 0x31 | 1319 | #define MBX_HEARTBEAT 0x31 |
1294 | #define MBX_WRITE_VPARMS 0x32 | 1320 | #define MBX_WRITE_VPARMS 0x32 |
1295 | #define MBX_ASYNCEVT_ENABLE 0x33 | 1321 | #define MBX_ASYNCEVT_ENABLE 0x33 |
@@ -2599,6 +2625,40 @@ typedef struct { | |||
2599 | 2625 | ||
2600 | } CONFIG_PORT_VAR; | 2626 | } CONFIG_PORT_VAR; |
2601 | 2627 | ||
2628 | /* Structure for MB Command CONFIG_MSI (0x30) */ | ||
2629 | struct config_msi_var { | ||
2630 | #ifdef __BIG_ENDIAN_BITFIELD | ||
2631 | uint32_t dfltMsgNum:8; /* Default message number */ | ||
2632 | uint32_t rsvd1:11; /* Reserved */ | ||
2633 | uint32_t NID:5; /* Number of secondary attention IDs */ | ||
2634 | uint32_t rsvd2:5; /* Reserved */ | ||
2635 | uint32_t dfltPresent:1; /* Default message number present */ | ||
2636 | uint32_t addFlag:1; /* Add association flag */ | ||
2637 | uint32_t reportFlag:1; /* Report association flag */ | ||
2638 | #else /* __LITTLE_ENDIAN_BITFIELD */ | ||
2639 | uint32_t reportFlag:1; /* Report association flag */ | ||
2640 | uint32_t addFlag:1; /* Add association flag */ | ||
2641 | uint32_t dfltPresent:1; /* Default message number present */ | ||
2642 | uint32_t rsvd2:5; /* Reserved */ | ||
2643 | uint32_t NID:5; /* Number of secondary attention IDs */ | ||
2644 | uint32_t rsvd1:11; /* Reserved */ | ||
2645 | uint32_t dfltMsgNum:8; /* Default message number */ | ||
2646 | #endif | ||
2647 | uint32_t attentionConditions[2]; | ||
2648 | uint8_t attentionId[16]; | ||
2649 | uint8_t messageNumberByHA[64]; | ||
2650 | uint8_t messageNumberByID[16]; | ||
2651 | uint32_t autoClearHA[2]; | ||
2652 | #ifdef __BIG_ENDIAN_BITFIELD | ||
2653 | uint32_t rsvd3:16; | ||
2654 | uint32_t autoClearID:16; | ||
2655 | #else /* __LITTLE_ENDIAN_BITFIELD */ | ||
2656 | uint32_t autoClearID:16; | ||
2657 | uint32_t rsvd3:16; | ||
2658 | #endif | ||
2659 | uint32_t rsvd4; | ||
2660 | }; | ||
2661 | |||
2602 | /* SLI-2 Port Control Block */ | 2662 | /* SLI-2 Port Control Block */ |
2603 | 2663 | ||
2604 | /* SLIM POINTER */ | 2664 | /* SLIM POINTER */ |
@@ -2722,6 +2782,7 @@ typedef union { | |||
2722 | REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ | 2782 | REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ |
2723 | UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ | 2783 | UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ |
2724 | ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ | 2784 | ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ |
2785 | struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI) */ | ||
2725 | } MAILVARIANTS; | 2786 | } MAILVARIANTS; |
2726 | 2787 | ||
2727 | /* | 2788 | /* |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 333166b17908..49577d5f130f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -389,6 +389,29 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
389 | if (phba->sli_rev != 3) | 389 | if (phba->sli_rev != 3) |
390 | lpfc_post_rcv_buf(phba); | 390 | lpfc_post_rcv_buf(phba); |
391 | 391 | ||
392 | /* | ||
393 | * Configure HBA MSI-X attention conditions to messages if MSI-X mode | ||
394 | */ | ||
395 | if (phba->intr_type == MSIX) { | ||
396 | rc = lpfc_config_msi(phba, pmb); | ||
397 | if (rc) { | ||
398 | mempool_free(pmb, phba->mbox_mem_pool); | ||
399 | return -EIO; | ||
400 | } | ||
401 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); | ||
402 | if (rc != MBX_SUCCESS) { | ||
403 | lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, | ||
404 | "0352 Config MSI mailbox command " | ||
405 | "failed, mbxCmd x%x, mbxStatus x%x\n", | ||
406 | pmb->mb.mbxCommand, pmb->mb.mbxStatus); | ||
407 | mempool_free(pmb, phba->mbox_mem_pool); | ||
408 | return -EIO; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | /* Initialize ERATT handling flag */ | ||
413 | phba->hba_flag &= ~HBA_ERATT_HANDLED; | ||
414 | |||
392 | /* Enable appropriate host interrupts */ | 415 | /* Enable appropriate host interrupts */ |
393 | spin_lock_irq(&phba->hbalock); | 416 | spin_lock_irq(&phba->hbalock); |
394 | status = readl(phba->HCregaddr); | 417 | status = readl(phba->HCregaddr); |
@@ -404,20 +427,21 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
404 | 427 | ||
405 | if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) && | 428 | if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) && |
406 | (phba->cfg_poll & DISABLE_FCP_RING_INT)) | 429 | (phba->cfg_poll & DISABLE_FCP_RING_INT)) |
407 | status &= ~(HC_R0INT_ENA << LPFC_FCP_RING); | 430 | status &= ~(HC_R0INT_ENA); |
408 | 431 | ||
409 | writel(status, phba->HCregaddr); | 432 | writel(status, phba->HCregaddr); |
410 | readl(phba->HCregaddr); /* flush */ | 433 | readl(phba->HCregaddr); /* flush */ |
411 | spin_unlock_irq(&phba->hbalock); | 434 | spin_unlock_irq(&phba->hbalock); |
412 | 435 | ||
413 | /* | 436 | /* Set up ring-0 (ELS) timer */ |
414 | * Setup the ring 0 (els) timeout handler | 437 | timeout = phba->fc_ratov * 2; |
415 | */ | ||
416 | timeout = phba->fc_ratov << 1; | ||
417 | mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); | 438 | mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); |
439 | /* Set up heart beat (HB) timer */ | ||
418 | mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL); | 440 | mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL); |
419 | phba->hb_outstanding = 0; | 441 | phba->hb_outstanding = 0; |
420 | phba->last_completion_time = jiffies; | 442 | phba->last_completion_time = jiffies; |
443 | /* Set up error attention (ERATT) polling timer */ | ||
444 | mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); | ||
421 | 445 | ||
422 | lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); | 446 | lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); |
423 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | 447 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
@@ -581,12 +605,15 @@ lpfc_hb_timeout(unsigned long ptr) | |||
581 | unsigned long iflag; | 605 | unsigned long iflag; |
582 | 606 | ||
583 | phba = (struct lpfc_hba *)ptr; | 607 | phba = (struct lpfc_hba *)ptr; |
608 | |||
609 | /* Check for heart beat timeout conditions */ | ||
584 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); | 610 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); |
585 | tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; | 611 | tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; |
586 | if (!tmo_posted) | 612 | if (!tmo_posted) |
587 | phba->pport->work_port_events |= WORKER_HB_TMO; | 613 | phba->pport->work_port_events |= WORKER_HB_TMO; |
588 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); | 614 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); |
589 | 615 | ||
616 | /* Tell the worker thread there is work to do */ | ||
590 | if (!tmo_posted) | 617 | if (!tmo_posted) |
591 | lpfc_worker_wake_up(phba); | 618 | lpfc_worker_wake_up(phba); |
592 | return; | 619 | return; |
@@ -617,6 +644,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) | |||
617 | phba->hb_outstanding = 0; | 644 | phba->hb_outstanding = 0; |
618 | spin_unlock_irqrestore(&phba->hbalock, drvr_flag); | 645 | spin_unlock_irqrestore(&phba->hbalock, drvr_flag); |
619 | 646 | ||
647 | /* Check and reset heart-beat timer is necessary */ | ||
620 | mempool_free(pmboxq, phba->mbox_mem_pool); | 648 | mempool_free(pmboxq, phba->mbox_mem_pool); |
621 | if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && | 649 | if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && |
622 | !(phba->link_state == LPFC_HBA_ERROR) && | 650 | !(phba->link_state == LPFC_HBA_ERROR) && |
@@ -856,8 +884,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | |||
856 | 884 | ||
857 | } else { | 885 | } else { |
858 | /* The if clause above forces this code path when the status | 886 | /* The if clause above forces this code path when the status |
859 | * failure is a value other than FFER6. Do not call the offline | 887 | * failure is a value other than FFER6. Do not call the offline |
860 | * twice. This is the adapter hardware error path. | 888 | * twice. This is the adapter hardware error path. |
861 | */ | 889 | */ |
862 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 890 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
863 | "0457 Adapter Hardware Error " | 891 | "0457 Adapter Hardware Error " |
@@ -873,6 +901,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | |||
873 | 901 | ||
874 | lpfc_offline_eratt(phba); | 902 | lpfc_offline_eratt(phba); |
875 | } | 903 | } |
904 | return; | ||
876 | } | 905 | } |
877 | 906 | ||
878 | /** | 907 | /** |
@@ -1656,6 +1685,7 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba) | |||
1656 | del_timer_sync(&phba->fabric_block_timer); | 1685 | del_timer_sync(&phba->fabric_block_timer); |
1657 | phba->hb_outstanding = 0; | 1686 | phba->hb_outstanding = 0; |
1658 | del_timer_sync(&phba->hb_tmofunc); | 1687 | del_timer_sync(&phba->hb_tmofunc); |
1688 | del_timer_sync(&phba->eratt_poll); | ||
1659 | return; | 1689 | return; |
1660 | } | 1690 | } |
1661 | 1691 | ||
@@ -2172,30 +2202,97 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) | |||
2172 | static int | 2202 | static int |
2173 | lpfc_enable_msix(struct lpfc_hba *phba) | 2203 | lpfc_enable_msix(struct lpfc_hba *phba) |
2174 | { | 2204 | { |
2175 | int error; | 2205 | int rc, i; |
2206 | LPFC_MBOXQ_t *pmb; | ||
2176 | 2207 | ||
2177 | phba->msix_entries[0].entry = 0; | 2208 | /* Set up MSI-X multi-message vectors */ |
2178 | phba->msix_entries[0].vector = 0; | 2209 | for (i = 0; i < LPFC_MSIX_VECTORS; i++) |
2210 | phba->msix_entries[i].entry = i; | ||
2179 | 2211 | ||
2180 | error = pci_enable_msix(phba->pcidev, phba->msix_entries, | 2212 | /* Configure MSI-X capability structure */ |
2213 | rc = pci_enable_msix(phba->pcidev, phba->msix_entries, | ||
2181 | ARRAY_SIZE(phba->msix_entries)); | 2214 | ARRAY_SIZE(phba->msix_entries)); |
2182 | if (error) { | 2215 | if (rc) { |
2183 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 2216 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
2184 | "0420 Enable MSI-X failed (%d), continuing " | 2217 | "0420 Enable MSI-X failed (%d), continuing " |
2185 | "with MSI\n", error); | 2218 | "with MSI\n", rc); |
2186 | pci_disable_msix(phba->pcidev); | 2219 | goto msi_fail_out; |
2187 | return error; | 2220 | } else |
2221 | for (i = 0; i < LPFC_MSIX_VECTORS; i++) | ||
2222 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2223 | "0477 MSI-X entry[%d]: vector=x%x " | ||
2224 | "message=%d\n", i, | ||
2225 | phba->msix_entries[i].vector, | ||
2226 | phba->msix_entries[i].entry); | ||
2227 | /* | ||
2228 | * Assign MSI-X vectors to interrupt handlers | ||
2229 | */ | ||
2230 | |||
2231 | /* vector-0 is associated to slow-path handler */ | ||
2232 | rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler, | ||
2233 | IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba); | ||
2234 | if (rc) { | ||
2235 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2236 | "0421 MSI-X slow-path request_irq failed " | ||
2237 | "(%d), continuing with MSI\n", rc); | ||
2238 | goto msi_fail_out; | ||
2188 | } | 2239 | } |
2189 | 2240 | ||
2190 | error = request_irq(phba->msix_entries[0].vector, lpfc_intr_handler, 0, | 2241 | /* vector-1 is associated to fast-path handler */ |
2191 | LPFC_DRIVER_NAME, phba); | 2242 | rc = request_irq(phba->msix_entries[1].vector, &lpfc_fp_intr_handler, |
2192 | if (error) { | 2243 | IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba); |
2244 | |||
2245 | if (rc) { | ||
2193 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 2246 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
2194 | "0421 MSI-X request_irq failed (%d), " | 2247 | "0429 MSI-X fast-path request_irq failed " |
2195 | "continuing with MSI\n", error); | 2248 | "(%d), continuing with MSI\n", rc); |
2196 | pci_disable_msix(phba->pcidev); | 2249 | goto irq_fail_out; |
2197 | } | 2250 | } |
2198 | return error; | 2251 | |
2252 | /* | ||
2253 | * Configure HBA MSI-X attention conditions to messages | ||
2254 | */ | ||
2255 | pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
2256 | |||
2257 | if (!pmb) { | ||
2258 | rc = -ENOMEM; | ||
2259 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2260 | "0474 Unable to allocate memory for issuing " | ||
2261 | "MBOX_CONFIG_MSI command\n"); | ||
2262 | goto mem_fail_out; | ||
2263 | } | ||
2264 | rc = lpfc_config_msi(phba, pmb); | ||
2265 | if (rc) | ||
2266 | goto mbx_fail_out; | ||
2267 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); | ||
2268 | if (rc != MBX_SUCCESS) { | ||
2269 | lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, | ||
2270 | "0351 Config MSI mailbox command failed, " | ||
2271 | "mbxCmd x%x, mbxStatus x%x\n", | ||
2272 | pmb->mb.mbxCommand, pmb->mb.mbxStatus); | ||
2273 | goto mbx_fail_out; | ||
2274 | } | ||
2275 | |||
2276 | /* Free memory allocated for mailbox command */ | ||
2277 | mempool_free(pmb, phba->mbox_mem_pool); | ||
2278 | return rc; | ||
2279 | |||
2280 | mbx_fail_out: | ||
2281 | /* Free memory allocated for mailbox command */ | ||
2282 | mempool_free(pmb, phba->mbox_mem_pool); | ||
2283 | |||
2284 | mem_fail_out: | ||
2285 | /* free the irq already requested */ | ||
2286 | free_irq(phba->msix_entries[1].vector, phba); | ||
2287 | |||
2288 | irq_fail_out: | ||
2289 | /* free the irq already requested */ | ||
2290 | free_irq(phba->msix_entries[0].vector, phba); | ||
2291 | |||
2292 | msi_fail_out: | ||
2293 | /* Unconfigure MSI-X capability structure */ | ||
2294 | pci_disable_msix(phba->pcidev); | ||
2295 | return rc; | ||
2199 | } | 2296 | } |
2200 | 2297 | ||
2201 | /** | 2298 | /** |
@@ -2208,7 +2305,12 @@ lpfc_enable_msix(struct lpfc_hba *phba) | |||
2208 | static void | 2305 | static void |
2209 | lpfc_disable_msix(struct lpfc_hba *phba) | 2306 | lpfc_disable_msix(struct lpfc_hba *phba) |
2210 | { | 2307 | { |
2211 | free_irq(phba->msix_entries[0].vector, phba); | 2308 | int i; |
2309 | |||
2310 | /* Free up MSI-X multi-message vectors */ | ||
2311 | for (i = 0; i < LPFC_MSIX_VECTORS; i++) | ||
2312 | free_irq(phba->msix_entries[i].vector, phba); | ||
2313 | /* Disable MSI-X */ | ||
2212 | pci_disable_msix(phba->pcidev); | 2314 | pci_disable_msix(phba->pcidev); |
2213 | } | 2315 | } |
2214 | 2316 | ||
@@ -2288,6 +2390,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2288 | init_timer(&phba->fabric_block_timer); | 2390 | init_timer(&phba->fabric_block_timer); |
2289 | phba->fabric_block_timer.function = lpfc_fabric_block_timeout; | 2391 | phba->fabric_block_timer.function = lpfc_fabric_block_timeout; |
2290 | phba->fabric_block_timer.data = (unsigned long) phba; | 2392 | phba->fabric_block_timer.data = (unsigned long) phba; |
2393 | init_timer(&phba->eratt_poll); | ||
2394 | phba->eratt_poll.function = lpfc_poll_eratt; | ||
2395 | phba->eratt_poll.data = (unsigned long) phba; | ||
2291 | 2396 | ||
2292 | pci_set_master(pdev); | 2397 | pci_set_master(pdev); |
2293 | pci_try_set_mwi(pdev); | 2398 | pci_try_set_mwi(pdev); |
@@ -2307,7 +2412,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2307 | bar2map_len = pci_resource_len(phba->pcidev, 2); | 2412 | bar2map_len = pci_resource_len(phba->pcidev, 2); |
2308 | 2413 | ||
2309 | /* Map HBA SLIM to a kernel virtual address. */ | 2414 | /* Map HBA SLIM to a kernel virtual address. */ |
2310 | phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); | 2415 | phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); |
2311 | if (!phba->slim_memmap_p) { | 2416 | if (!phba->slim_memmap_p) { |
2312 | error = -ENODEV; | 2417 | error = -ENODEV; |
2313 | dev_printk(KERN_ERR, &pdev->dev, | 2418 | dev_printk(KERN_ERR, &pdev->dev, |
@@ -2405,7 +2510,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2405 | phba->fc_arbtov = FF_DEF_ARBTOV; | 2510 | phba->fc_arbtov = FF_DEF_ARBTOV; |
2406 | 2511 | ||
2407 | INIT_LIST_HEAD(&phba->work_list); | 2512 | INIT_LIST_HEAD(&phba->work_list); |
2408 | phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); | 2513 | phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); |
2409 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); | 2514 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); |
2410 | 2515 | ||
2411 | /* Initialize the wait queue head for the kernel thread */ | 2516 | /* Initialize the wait queue head for the kernel thread */ |
@@ -2440,21 +2545,42 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2440 | pci_set_drvdata(pdev, shost); | 2545 | pci_set_drvdata(pdev, shost); |
2441 | phba->intr_type = NONE; | 2546 | phba->intr_type = NONE; |
2442 | 2547 | ||
2548 | phba->MBslimaddr = phba->slim_memmap_p; | ||
2549 | phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; | ||
2550 | phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; | ||
2551 | phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; | ||
2552 | phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; | ||
2553 | |||
2554 | /* Configure and enable interrupt */ | ||
2443 | if (phba->cfg_use_msi == 2) { | 2555 | if (phba->cfg_use_msi == 2) { |
2444 | error = lpfc_enable_msix(phba); | 2556 | /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ |
2445 | if (!error) | 2557 | error = lpfc_sli_config_port(phba, 3); |
2446 | phba->intr_type = MSIX; | 2558 | if (error) |
2559 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2560 | "0427 Firmware not capable of SLI 3 mode.\n"); | ||
2561 | else { | ||
2562 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2563 | "0426 Firmware capable of SLI 3 mode.\n"); | ||
2564 | /* Now, try to enable MSI-X interrupt mode */ | ||
2565 | error = lpfc_enable_msix(phba); | ||
2566 | if (!error) { | ||
2567 | phba->intr_type = MSIX; | ||
2568 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2569 | "0430 enable MSI-X mode.\n"); | ||
2570 | } | ||
2571 | } | ||
2447 | } | 2572 | } |
2448 | 2573 | ||
2449 | /* Fallback to MSI if MSI-X initialization failed */ | 2574 | /* Fallback to MSI if MSI-X initialization failed */ |
2450 | if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { | 2575 | if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { |
2451 | retval = pci_enable_msi(phba->pcidev); | 2576 | retval = pci_enable_msi(phba->pcidev); |
2452 | if (!retval) | 2577 | if (!retval) { |
2453 | phba->intr_type = MSI; | 2578 | phba->intr_type = MSI; |
2454 | else | ||
2455 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 2579 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
2456 | "0452 Enable MSI failed, continuing " | 2580 | "0473 enable MSI mode.\n"); |
2457 | "with IRQ\n"); | 2581 | } else |
2582 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2583 | "0452 enable IRQ mode.\n"); | ||
2458 | } | 2584 | } |
2459 | 2585 | ||
2460 | /* MSI-X is the only case the doesn't need to call request_irq */ | 2586 | /* MSI-X is the only case the doesn't need to call request_irq */ |
@@ -2470,18 +2596,16 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2470 | phba->intr_type = INTx; | 2596 | phba->intr_type = INTx; |
2471 | } | 2597 | } |
2472 | 2598 | ||
2473 | phba->MBslimaddr = phba->slim_memmap_p; | ||
2474 | phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; | ||
2475 | phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; | ||
2476 | phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; | ||
2477 | phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; | ||
2478 | |||
2479 | if (lpfc_alloc_sysfs_attr(vport)) { | 2599 | if (lpfc_alloc_sysfs_attr(vport)) { |
2600 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2601 | "1476 Failed to allocate sysfs attr\n"); | ||
2480 | error = -ENOMEM; | 2602 | error = -ENOMEM; |
2481 | goto out_free_irq; | 2603 | goto out_free_irq; |
2482 | } | 2604 | } |
2483 | 2605 | ||
2484 | if (lpfc_sli_hba_setup(phba)) { | 2606 | if (lpfc_sli_hba_setup(phba)) { |
2607 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2608 | "1477 Failed to set up hba\n"); | ||
2485 | error = -ENODEV; | 2609 | error = -ENODEV; |
2486 | goto out_remove_device; | 2610 | goto out_remove_device; |
2487 | } | 2611 | } |
@@ -2500,6 +2624,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2500 | spin_unlock_irq(shost->host_lock); | 2624 | spin_unlock_irq(shost->host_lock); |
2501 | } | 2625 | } |
2502 | 2626 | ||
2627 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2628 | "0428 Perform SCSI scan\n"); | ||
2503 | scsi_scan_host(shost); | 2629 | scsi_scan_host(shost); |
2504 | 2630 | ||
2505 | return 0; | 2631 | return 0; |
@@ -2732,20 +2858,34 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) | |||
2732 | /* Enable configured interrupt method */ | 2858 | /* Enable configured interrupt method */ |
2733 | phba->intr_type = NONE; | 2859 | phba->intr_type = NONE; |
2734 | if (phba->cfg_use_msi == 2) { | 2860 | if (phba->cfg_use_msi == 2) { |
2735 | error = lpfc_enable_msix(phba); | 2861 | /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ |
2736 | if (!error) | 2862 | error = lpfc_sli_config_port(phba, 3); |
2737 | phba->intr_type = MSIX; | 2863 | if (error) |
2864 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2865 | "0478 Firmware not capable of SLI 3 mode.\n"); | ||
2866 | else { | ||
2867 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2868 | "0479 Firmware capable of SLI 3 mode.\n"); | ||
2869 | /* Now, try to enable MSI-X interrupt mode */ | ||
2870 | error = lpfc_enable_msix(phba); | ||
2871 | if (!error) { | ||
2872 | phba->intr_type = MSIX; | ||
2873 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2874 | "0480 enable MSI-X mode.\n"); | ||
2875 | } | ||
2876 | } | ||
2738 | } | 2877 | } |
2739 | 2878 | ||
2740 | /* Fallback to MSI if MSI-X initialization failed */ | 2879 | /* Fallback to MSI if MSI-X initialization failed */ |
2741 | if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { | 2880 | if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { |
2742 | retval = pci_enable_msi(phba->pcidev); | 2881 | retval = pci_enable_msi(phba->pcidev); |
2743 | if (!retval) | 2882 | if (!retval) { |
2744 | phba->intr_type = MSI; | 2883 | phba->intr_type = MSI; |
2745 | else | ||
2746 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 2884 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
2747 | "0470 Enable MSI failed, continuing " | 2885 | "0481 enable MSI mode.\n"); |
2748 | "with IRQ\n"); | 2886 | } else |
2887 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2888 | "0470 enable IRQ mode.\n"); | ||
2749 | } | 2889 | } |
2750 | 2890 | ||
2751 | /* MSI-X is the only case the doesn't need to call request_irq */ | 2891 | /* MSI-X is the only case the doesn't need to call request_irq */ |
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index ca358355ec9b..65bc8e1a5f7d 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-2007 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2008 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 * |
@@ -272,6 +272,84 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
272 | } | 272 | } |
273 | 273 | ||
274 | /** | 274 | /** |
275 | * lpfc_config_msi: Prepare a mailbox command for configuring msi-x. | ||
276 | * @phba: pointer to lpfc hba data structure. | ||
277 | * @pmb: pointer to the driver internal queue element for mailbox command. | ||
278 | * | ||
279 | * The configure MSI-X mailbox command is used to configure the HBA's SLI-3 | ||
280 | * MSI-X multi-message interrupt vector association to interrupt attention | ||
281 | * conditions. | ||
282 | * | ||
283 | * Return codes | ||
284 | * 0 - Success | ||
285 | * -EINVAL - Failure | ||
286 | **/ | ||
287 | int | ||
288 | lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | ||
289 | { | ||
290 | MAILBOX_t *mb = &pmb->mb; | ||
291 | uint32_t attentionConditions[2]; | ||
292 | |||
293 | /* Sanity check */ | ||
294 | if (phba->cfg_use_msi != 2) { | ||
295 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
296 | "0475 Not configured for supporting MSI-X " | ||
297 | "cfg_use_msi: 0x%x\n", phba->cfg_use_msi); | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | |||
301 | if (phba->sli_rev < 3) { | ||
302 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
303 | "0476 HBA not supporting SLI-3 or later " | ||
304 | "SLI Revision: 0x%x\n", phba->sli_rev); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | /* Clear mailbox command fields */ | ||
309 | memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); | ||
310 | |||
311 | /* | ||
312 | * SLI-3, Message Signaled Interrupt Fearure. | ||
313 | */ | ||
314 | |||
315 | /* Multi-message attention configuration */ | ||
316 | attentionConditions[0] = (HA_R0ATT | HA_R1ATT | HA_R2ATT | HA_ERATT | | ||
317 | HA_LATT | HA_MBATT); | ||
318 | attentionConditions[1] = 0; | ||
319 | |||
320 | mb->un.varCfgMSI.attentionConditions[0] = attentionConditions[0]; | ||
321 | mb->un.varCfgMSI.attentionConditions[1] = attentionConditions[1]; | ||
322 | |||
323 | /* | ||
324 | * Set up message number to HA bit association | ||
325 | */ | ||
326 | #ifdef __BIG_ENDIAN_BITFIELD | ||
327 | /* RA0 (FCP Ring) */ | ||
328 | mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS] = 1; | ||
329 | /* RA1 (Other Protocol Extra Ring) */ | ||
330 | mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS] = 1; | ||
331 | #else /* __LITTLE_ENDIAN_BITFIELD */ | ||
332 | /* RA0 (FCP Ring) */ | ||
333 | mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS^3] = 1; | ||
334 | /* RA1 (Other Protocol Extra Ring) */ | ||
335 | mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS^3] = 1; | ||
336 | #endif | ||
337 | /* Multi-message interrupt autoclear configuration*/ | ||
338 | mb->un.varCfgMSI.autoClearHA[0] = attentionConditions[0]; | ||
339 | mb->un.varCfgMSI.autoClearHA[1] = attentionConditions[1]; | ||
340 | |||
341 | /* For now, HBA autoclear does not work reliably, disable it */ | ||
342 | mb->un.varCfgMSI.autoClearHA[0] = 0; | ||
343 | mb->un.varCfgMSI.autoClearHA[1] = 0; | ||
344 | |||
345 | /* Set command and owner bit */ | ||
346 | mb->mbxCommand = MBX_CONFIG_MSI; | ||
347 | mb->mbxOwner = OWN_HOST; | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /** | ||
275 | * lpfc_init_link: Prepare a mailbox command for initialize link on a HBA. | 353 | * lpfc_init_link: Prepare a mailbox command for initialize link on a HBA. |
276 | * @phba: pointer to lpfc hba data structure. | 354 | * @phba: pointer to lpfc hba data structure. |
277 | * @pmb: pointer to the driver internal queue element for mailbox command. | 355 | * @pmb: pointer to the driver internal queue element for mailbox command. |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1812e18246d5..2cca39e9b93d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -1699,6 +1699,36 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
1699 | } | 1699 | } |
1700 | 1700 | ||
1701 | /** | 1701 | /** |
1702 | * lpfc_poll_eratt: Error attention polling timer timeout handler. | ||
1703 | * @ptr: Pointer to address of HBA context object. | ||
1704 | * | ||
1705 | * This function is invoked by the Error Attention polling timer when the | ||
1706 | * timer times out. It will check the SLI Error Attention register for | ||
1707 | * possible attention events. If so, it will post an Error Attention event | ||
1708 | * and wake up worker thread to process it. Otherwise, it will set up the | ||
1709 | * Error Attention polling timer for the next poll. | ||
1710 | **/ | ||
1711 | void lpfc_poll_eratt(unsigned long ptr) | ||
1712 | { | ||
1713 | struct lpfc_hba *phba; | ||
1714 | uint32_t eratt = 0; | ||
1715 | |||
1716 | phba = (struct lpfc_hba *)ptr; | ||
1717 | |||
1718 | /* Check chip HA register for error event */ | ||
1719 | eratt = lpfc_sli_check_eratt(phba); | ||
1720 | |||
1721 | if (eratt) | ||
1722 | /* Tell the worker thread there is work to do */ | ||
1723 | lpfc_worker_wake_up(phba); | ||
1724 | else | ||
1725 | /* Restart the timer for next eratt poll */ | ||
1726 | mod_timer(&phba->eratt_poll, jiffies + | ||
1727 | HZ * LPFC_ERATT_POLL_INTERVAL); | ||
1728 | return; | ||
1729 | } | ||
1730 | |||
1731 | /** | ||
1702 | * lpfc_sli_poll_fcp_ring: Handle FCP ring completion in polling mode. | 1732 | * lpfc_sli_poll_fcp_ring: Handle FCP ring completion in polling mode. |
1703 | * @phba: Pointer to HBA context object. | 1733 | * @phba: Pointer to HBA context object. |
1704 | * | 1734 | * |
@@ -3011,7 +3041,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) | |||
3011 | } | 3041 | } |
3012 | 3042 | ||
3013 | /** | 3043 | /** |
3014 | * lpfc_do_config_port: Issue config port mailbox command. | 3044 | * lpfc_sli_config_port: Issue config port mailbox command. |
3015 | * @phba: Pointer to HBA context object. | 3045 | * @phba: Pointer to HBA context object. |
3016 | * @sli_mode: sli mode - 2/3 | 3046 | * @sli_mode: sli mode - 2/3 |
3017 | * | 3047 | * |
@@ -3023,8 +3053,8 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) | |||
3023 | * The function returns 0 if successful, else returns negative error | 3053 | * The function returns 0 if successful, else returns negative error |
3024 | * code. | 3054 | * code. |
3025 | **/ | 3055 | **/ |
3026 | static int | 3056 | int |
3027 | lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode) | 3057 | lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) |
3028 | { | 3058 | { |
3029 | LPFC_MBOXQ_t *pmb; | 3059 | LPFC_MBOXQ_t *pmb; |
3030 | uint32_t resetcount = 0, rc = 0, done = 0; | 3060 | uint32_t resetcount = 0, rc = 0, done = 0; |
@@ -3165,13 +3195,14 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) | |||
3165 | break; | 3195 | break; |
3166 | } | 3196 | } |
3167 | 3197 | ||
3168 | rc = lpfc_do_config_port(phba, mode); | 3198 | rc = lpfc_sli_config_port(phba, mode); |
3199 | |||
3169 | if (rc && lpfc_sli_mode == 3) | 3200 | if (rc && lpfc_sli_mode == 3) |
3170 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, | 3201 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, |
3171 | "1820 Unable to select SLI-3. " | 3202 | "1820 Unable to select SLI-3. " |
3172 | "Not supported by adapter.\n"); | 3203 | "Not supported by adapter.\n"); |
3173 | if (rc && mode != 2) | 3204 | if (rc && mode != 2) |
3174 | rc = lpfc_do_config_port(phba, 2); | 3205 | rc = lpfc_sli_config_port(phba, 2); |
3175 | if (rc) | 3206 | if (rc) |
3176 | goto lpfc_sli_hba_setup_error; | 3207 | goto lpfc_sli_hba_setup_error; |
3177 | 3208 | ||
@@ -3192,8 +3223,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) | |||
3192 | if (rc) | 3223 | if (rc) |
3193 | goto lpfc_sli_hba_setup_error; | 3224 | goto lpfc_sli_hba_setup_error; |
3194 | 3225 | ||
3195 | /* Init HBQs */ | 3226 | /* Init HBQs */ |
3196 | |||
3197 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | 3227 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { |
3198 | rc = lpfc_sli_hbq_setup(phba); | 3228 | rc = lpfc_sli_hbq_setup(phba); |
3199 | if (rc) | 3229 | if (rc) |
@@ -5128,28 +5158,73 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) | |||
5128 | } | 5158 | } |
5129 | 5159 | ||
5130 | /** | 5160 | /** |
5131 | * lpfc_intr_handler: The interrupt handler of lpfc driver. | 5161 | * lpfc_sli_check_eratt: check error attention events |
5162 | * @phba: Pointer to HBA context. | ||
5163 | * | ||
5164 | * This function is called form timer soft interrupt context to check HBA's | ||
5165 | * error attention register bit for error attention events. | ||
5166 | * | ||
5167 | * This fucntion returns 1 when there is Error Attention in the Host Attention | ||
5168 | * Register and returns 0 otherwise. | ||
5169 | **/ | ||
5170 | int | ||
5171 | lpfc_sli_check_eratt(struct lpfc_hba *phba) | ||
5172 | { | ||
5173 | uint32_t ha_copy; | ||
5174 | |||
5175 | /* If somebody is waiting to handle an eratt, don't process it | ||
5176 | * here. The brdkill function will do this. | ||
5177 | */ | ||
5178 | if (phba->link_flag & LS_IGNORE_ERATT) | ||
5179 | return 0; | ||
5180 | |||
5181 | /* Check if interrupt handler handles this ERATT */ | ||
5182 | spin_lock_irq(&phba->hbalock); | ||
5183 | if (phba->hba_flag & HBA_ERATT_HANDLED) { | ||
5184 | /* Interrupt handler has handled ERATT */ | ||
5185 | spin_unlock_irq(&phba->hbalock); | ||
5186 | return 0; | ||
5187 | } | ||
5188 | |||
5189 | /* Read chip Host Attention (HA) register */ | ||
5190 | ha_copy = readl(phba->HAregaddr); | ||
5191 | if (ha_copy & HA_ERATT) { | ||
5192 | /* Read host status register to retrieve error event */ | ||
5193 | lpfc_sli_read_hs(phba); | ||
5194 | /* Set the driver HA work bitmap */ | ||
5195 | phba->work_ha |= HA_ERATT; | ||
5196 | /* Indicate polling handles this ERATT */ | ||
5197 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
5198 | spin_unlock_irq(&phba->hbalock); | ||
5199 | return 1; | ||
5200 | } | ||
5201 | spin_unlock_irq(&phba->hbalock); | ||
5202 | return 0; | ||
5203 | } | ||
5204 | |||
5205 | /** | ||
5206 | * lpfc_sp_intr_handler: The slow-path interrupt handler of lpfc driver. | ||
5132 | * @irq: Interrupt number. | 5207 | * @irq: Interrupt number. |
5133 | * @dev_id: The device context pointer. | 5208 | * @dev_id: The device context pointer. |
5134 | * | 5209 | * |
5135 | * This function is called from the PCI layer when there is | 5210 | * This function is directly called from the PCI layer as an interrupt |
5136 | * an event in the HBA which requires driver attention. When | 5211 | * service routine when the device is enabled with MSI-X multi-message |
5137 | * the PCI slot is in error recovery or the HBA is undergoing | 5212 | * interrupt mode and there are slow-path events in the HBA. However, |
5138 | * initialization the interrupt handler will not process the | 5213 | * when the device is enabled with either MSI or Pin-IRQ interrupt mode, |
5139 | * interrupt. | 5214 | * this function is called as part of the device-level interrupt handler. |
5140 | * The error attention, link attention and els ring attention | 5215 | * When the PCI slot is in error recovery or the HBA is undergoing |
5141 | * events are handled by the worker thread. The interrupt | 5216 | * initialization, the interrupt handler will not process the interrupt. |
5142 | * handler signals the worker thread and returns for these | 5217 | * The link attention and ELS ring attention events are handled by the |
5143 | * events. | 5218 | * worker thread. The interrupt handler signals the worker thread and |
5144 | * The SCSI ring event and mailbox events are handled in the | 5219 | * and returns for these events. This function is called without any |
5145 | * interrupt context. | 5220 | * lock held. It gets the hbalock to access and update SLI data |
5146 | * This function is called without any lock held. It gets the | 5221 | * structures. |
5147 | * hbalock to access and update SLI data structures. | 5222 | * |
5148 | * This function returns IRQ_HANDLED when interrupt is handled | 5223 | * This function returns IRQ_HANDLED when interrupt is handled else it |
5149 | * else it returns IRQ_NONE. | 5224 | * returns IRQ_NONE. |
5150 | **/ | 5225 | **/ |
5151 | irqreturn_t | 5226 | irqreturn_t |
5152 | lpfc_intr_handler(int irq, void *dev_id) | 5227 | lpfc_sp_intr_handler(int irq, void *dev_id) |
5153 | { | 5228 | { |
5154 | struct lpfc_hba *phba; | 5229 | struct lpfc_hba *phba; |
5155 | uint32_t ha_copy; | 5230 | uint32_t ha_copy; |
@@ -5168,54 +5243,52 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
5168 | * Get the driver's phba structure from the dev_id and | 5243 | * Get the driver's phba structure from the dev_id and |
5169 | * assume the HBA is not interrupting. | 5244 | * assume the HBA is not interrupting. |
5170 | */ | 5245 | */ |
5171 | phba = (struct lpfc_hba *) dev_id; | 5246 | phba = (struct lpfc_hba *)dev_id; |
5172 | 5247 | ||
5173 | if (unlikely(!phba)) | 5248 | if (unlikely(!phba)) |
5174 | return IRQ_NONE; | 5249 | return IRQ_NONE; |
5175 | 5250 | ||
5176 | /* If the pci channel is offline, ignore all the interrupts. */ | ||
5177 | if (unlikely(pci_channel_offline(phba->pcidev))) | ||
5178 | return IRQ_NONE; | ||
5179 | |||
5180 | phba->sli.slistat.sli_intr++; | ||
5181 | |||
5182 | /* | 5251 | /* |
5183 | * Call the HBA to see if it is interrupting. If not, don't claim | 5252 | * Stuff needs to be attented to when this function is invoked as an |
5184 | * the interrupt | 5253 | * individual interrupt handler in MSI-X multi-message interrupt mode |
5185 | */ | 5254 | */ |
5186 | 5255 | if (phba->intr_type == MSIX) { | |
5187 | /* Ignore all interrupts during initialization. */ | 5256 | /* If the pci channel is offline, ignore all the interrupts */ |
5188 | if (unlikely(phba->link_state < LPFC_LINK_DOWN)) | 5257 | if (unlikely(pci_channel_offline(phba->pcidev))) |
5189 | return IRQ_NONE; | 5258 | return IRQ_NONE; |
5190 | 5259 | /* Update device-level interrupt statistics */ | |
5191 | /* | 5260 | phba->sli.slistat.sli_intr++; |
5192 | * Read host attention register to determine interrupt source | 5261 | /* Ignore all interrupts during initialization. */ |
5193 | * Clear Attention Sources, except Error Attention (to | 5262 | if (unlikely(phba->link_state < LPFC_LINK_DOWN)) |
5194 | * preserve status) and Link Attention | 5263 | return IRQ_NONE; |
5195 | */ | 5264 | /* Need to read HA REG for slow-path events */ |
5196 | spin_lock(&phba->hbalock); | 5265 | spin_lock(&phba->hbalock); |
5197 | if (phba->sli3_options & LPFC_SLI3_INB_ENABLED && | ||
5198 | (phba->inb_last_counter != *phba->inb_counter)) { | ||
5199 | phba->inb_last_counter = *phba->inb_counter; | ||
5200 | ha_copy = le32_to_cpu(*phba->inb_ha_copy); | ||
5201 | } else | ||
5202 | ha_copy = readl(phba->HAregaddr); | 5266 | ha_copy = readl(phba->HAregaddr); |
5203 | if (unlikely(!ha_copy)) { | 5267 | /* If somebody is waiting to handle an eratt don't process it |
5268 | * here. The brdkill function will do this. | ||
5269 | */ | ||
5270 | if (phba->link_flag & LS_IGNORE_ERATT) | ||
5271 | ha_copy &= ~HA_ERATT; | ||
5272 | /* Check the need for handling ERATT in interrupt handler */ | ||
5273 | if (ha_copy & HA_ERATT) { | ||
5274 | if (phba->hba_flag & HBA_ERATT_HANDLED) | ||
5275 | /* ERATT polling has handled ERATT */ | ||
5276 | ha_copy &= ~HA_ERATT; | ||
5277 | else | ||
5278 | /* Indicate interrupt handler handles ERATT */ | ||
5279 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
5280 | } | ||
5281 | /* Clear up only attention source related to slow-path */ | ||
5282 | writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), | ||
5283 | phba->HAregaddr); | ||
5284 | readl(phba->HAregaddr); /* flush */ | ||
5204 | spin_unlock(&phba->hbalock); | 5285 | spin_unlock(&phba->hbalock); |
5205 | return IRQ_NONE; | 5286 | } else |
5206 | } | 5287 | ha_copy = phba->ha_copy; |
5207 | /* If somebody is waiting to handle an eratt don't process it | ||
5208 | * here. The brdkill function will do this. | ||
5209 | */ | ||
5210 | if (phba->link_flag & LS_IGNORE_ERATT) | ||
5211 | ha_copy &= ~HA_ERATT; | ||
5212 | writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); | ||
5213 | readl(phba->HAregaddr); /* flush */ | ||
5214 | spin_unlock(&phba->hbalock); | ||
5215 | 5288 | ||
5216 | work_ha_copy = ha_copy & phba->work_ha_mask; | 5289 | work_ha_copy = ha_copy & phba->work_ha_mask; |
5217 | 5290 | ||
5218 | if (unlikely(work_ha_copy)) { | 5291 | if (work_ha_copy) { |
5219 | if (work_ha_copy & HA_LATT) { | 5292 | if (work_ha_copy & HA_LATT) { |
5220 | if (phba->sli.sli_flag & LPFC_PROCESS_LA) { | 5293 | if (phba->sli.sli_flag & LPFC_PROCESS_LA) { |
5221 | /* | 5294 | /* |
@@ -5234,7 +5307,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
5234 | work_ha_copy &= ~HA_LATT; | 5307 | work_ha_copy &= ~HA_LATT; |
5235 | } | 5308 | } |
5236 | 5309 | ||
5237 | if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) { | 5310 | if (work_ha_copy & ~(HA_ERATT | HA_MBATT | HA_LATT)) { |
5238 | /* | 5311 | /* |
5239 | * Turn off Slow Rings interrupts, LPFC_ELS_RING is | 5312 | * Turn off Slow Rings interrupts, LPFC_ELS_RING is |
5240 | * the only slow ring. | 5313 | * the only slow ring. |
@@ -5275,28 +5348,10 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
5275 | spin_unlock(&phba->hbalock); | 5348 | spin_unlock(&phba->hbalock); |
5276 | } | 5349 | } |
5277 | } | 5350 | } |
5278 | |||
5279 | if (work_ha_copy & HA_ERATT) { | ||
5280 | /* | ||
5281 | * There was a link/board error. Read the | ||
5282 | * status register to retrieve the error event | ||
5283 | * and process it. | ||
5284 | */ | ||
5285 | phba->sli.slistat.err_attn_event++; | ||
5286 | /* Save status info */ | ||
5287 | phba->work_hs = readl(phba->HSregaddr); | ||
5288 | phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); | ||
5289 | phba->work_status[1] = readl(phba->MBslimaddr + 0xac); | ||
5290 | |||
5291 | /* Clear Chip error bit */ | ||
5292 | writel(HA_ERATT, phba->HAregaddr); | ||
5293 | readl(phba->HAregaddr); /* flush */ | ||
5294 | phba->pport->stopped = 1; | ||
5295 | } | ||
5296 | |||
5297 | spin_lock(&phba->hbalock); | 5351 | spin_lock(&phba->hbalock); |
5298 | if ((work_ha_copy & HA_MBATT) && | 5352 | if (work_ha_copy & HA_ERATT) |
5299 | (phba->sli.mbox_active)) { | 5353 | lpfc_sli_read_hs(phba); |
5354 | if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { | ||
5300 | pmb = phba->sli.mbox_active; | 5355 | pmb = phba->sli.mbox_active; |
5301 | pmbox = &pmb->mb; | 5356 | pmbox = &pmb->mb; |
5302 | mbox = phba->mbox; | 5357 | mbox = phba->mbox; |
@@ -5379,6 +5434,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
5379 | } | 5434 | } |
5380 | } else | 5435 | } else |
5381 | spin_unlock(&phba->hbalock); | 5436 | spin_unlock(&phba->hbalock); |
5437 | |||
5382 | if ((work_ha_copy & HA_MBATT) && | 5438 | if ((work_ha_copy & HA_MBATT) && |
5383 | (phba->sli.mbox_active == NULL)) { | 5439 | (phba->sli.mbox_active == NULL)) { |
5384 | send_current_mbox: | 5440 | send_current_mbox: |
@@ -5398,15 +5454,74 @@ send_current_mbox: | |||
5398 | spin_unlock(&phba->hbalock); | 5454 | spin_unlock(&phba->hbalock); |
5399 | lpfc_worker_wake_up(phba); | 5455 | lpfc_worker_wake_up(phba); |
5400 | } | 5456 | } |
5457 | return IRQ_HANDLED; | ||
5401 | 5458 | ||
5402 | ha_copy &= ~(phba->work_ha_mask); | 5459 | } /* lpfc_sp_intr_handler */ |
5460 | |||
5461 | /** | ||
5462 | * lpfc_fp_intr_handler: The fast-path interrupt handler of lpfc driver. | ||
5463 | * @irq: Interrupt number. | ||
5464 | * @dev_id: The device context pointer. | ||
5465 | * | ||
5466 | * This function is directly called from the PCI layer as an interrupt | ||
5467 | * service routine when the device is enabled with MSI-X multi-message | ||
5468 | * interrupt mode and there is a fast-path FCP IOCB ring event in the | ||
5469 | * HBA. However, when the device is enabled with either MSI or Pin-IRQ | ||
5470 | * interrupt mode, this function is called as part of the device-level | ||
5471 | * interrupt handler. When the PCI slot is in error recovery or the HBA | ||
5472 | * is undergoing initialization, the interrupt handler will not process | ||
5473 | * the interrupt. The SCSI FCP fast-path ring event are handled in the | ||
5474 | * intrrupt context. This function is called without any lock held. It | ||
5475 | * gets the hbalock to access and update SLI data structures. | ||
5476 | * | ||
5477 | * This function returns IRQ_HANDLED when interrupt is handled else it | ||
5478 | * returns IRQ_NONE. | ||
5479 | **/ | ||
5480 | irqreturn_t | ||
5481 | lpfc_fp_intr_handler(int irq, void *dev_id) | ||
5482 | { | ||
5483 | struct lpfc_hba *phba; | ||
5484 | uint32_t ha_copy; | ||
5485 | unsigned long status; | ||
5486 | |||
5487 | /* Get the driver's phba structure from the dev_id and | ||
5488 | * assume the HBA is not interrupting. | ||
5489 | */ | ||
5490 | phba = (struct lpfc_hba *) dev_id; | ||
5491 | |||
5492 | if (unlikely(!phba)) | ||
5493 | return IRQ_NONE; | ||
5494 | |||
5495 | /* | ||
5496 | * Stuff needs to be attented to when this function is invoked as an | ||
5497 | * individual interrupt handler in MSI-X multi-message interrupt mode | ||
5498 | */ | ||
5499 | if (phba->intr_type == MSIX) { | ||
5500 | /* If pci channel is offline, ignore all the interrupts */ | ||
5501 | if (unlikely(pci_channel_offline(phba->pcidev))) | ||
5502 | return IRQ_NONE; | ||
5503 | /* Update device-level interrupt statistics */ | ||
5504 | phba->sli.slistat.sli_intr++; | ||
5505 | /* Ignore all interrupts during initialization. */ | ||
5506 | if (unlikely(phba->link_state < LPFC_LINK_DOWN)) | ||
5507 | return IRQ_NONE; | ||
5508 | /* Need to read HA REG for FCP ring and other ring events */ | ||
5509 | ha_copy = readl(phba->HAregaddr); | ||
5510 | /* Clear up only attention source related to fast-path */ | ||
5511 | spin_lock(&phba->hbalock); | ||
5512 | writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), | ||
5513 | phba->HAregaddr); | ||
5514 | readl(phba->HAregaddr); /* flush */ | ||
5515 | spin_unlock(&phba->hbalock); | ||
5516 | } else | ||
5517 | ha_copy = phba->ha_copy; | ||
5403 | 5518 | ||
5404 | /* | 5519 | /* |
5405 | * Process all events on FCP ring. Take the optimized path for | 5520 | * Process all events on FCP ring. Take the optimized path for FCP IO. |
5406 | * FCP IO. Any other IO is slow path and is handled by | ||
5407 | * the worker thread. | ||
5408 | */ | 5521 | */ |
5409 | status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); | 5522 | ha_copy &= ~(phba->work_ha_mask); |
5523 | |||
5524 | status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); | ||
5410 | status >>= (4*LPFC_FCP_RING); | 5525 | status >>= (4*LPFC_FCP_RING); |
5411 | if (status & HA_RXMASK) | 5526 | if (status & HA_RXMASK) |
5412 | lpfc_sli_handle_fast_ring_event(phba, | 5527 | lpfc_sli_handle_fast_ring_event(phba, |
@@ -5415,11 +5530,10 @@ send_current_mbox: | |||
5415 | 5530 | ||
5416 | if (phba->cfg_multi_ring_support == 2) { | 5531 | if (phba->cfg_multi_ring_support == 2) { |
5417 | /* | 5532 | /* |
5418 | * Process all events on extra ring. Take the optimized path | 5533 | * Process all events on extra ring. Take the optimized path |
5419 | * for extra ring IO. Any other IO is slow path and is handled | 5534 | * for extra ring IO. |
5420 | * by the worker thread. | ||
5421 | */ | 5535 | */ |
5422 | status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); | 5536 | status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); |
5423 | status >>= (4*LPFC_EXTRA_RING); | 5537 | status >>= (4*LPFC_EXTRA_RING); |
5424 | if (status & HA_RXMASK) { | 5538 | if (status & HA_RXMASK) { |
5425 | lpfc_sli_handle_fast_ring_event(phba, | 5539 | lpfc_sli_handle_fast_ring_event(phba, |
@@ -5428,5 +5542,106 @@ send_current_mbox: | |||
5428 | } | 5542 | } |
5429 | } | 5543 | } |
5430 | return IRQ_HANDLED; | 5544 | return IRQ_HANDLED; |
5545 | } /* lpfc_fp_intr_handler */ | ||
5546 | |||
5547 | /** | ||
5548 | * lpfc_intr_handler: The device-level interrupt handler of lpfc driver. | ||
5549 | * @irq: Interrupt number. | ||
5550 | * @dev_id: The device context pointer. | ||
5551 | * | ||
5552 | * This function is the device-level interrupt handler called from the PCI | ||
5553 | * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is | ||
5554 | * an event in the HBA which requires driver attention. This function | ||
5555 | * invokes the slow-path interrupt attention handling function and fast-path | ||
5556 | * interrupt attention handling function in turn to process the relevant | ||
5557 | * HBA attention events. This function is called without any lock held. It | ||
5558 | * gets the hbalock to access and update SLI data structures. | ||
5559 | * | ||
5560 | * This function returns IRQ_HANDLED when interrupt is handled, else it | ||
5561 | * returns IRQ_NONE. | ||
5562 | **/ | ||
5563 | irqreturn_t | ||
5564 | lpfc_intr_handler(int irq, void *dev_id) | ||
5565 | { | ||
5566 | struct lpfc_hba *phba; | ||
5567 | irqreturn_t sp_irq_rc, fp_irq_rc; | ||
5568 | unsigned long status1, status2; | ||
5569 | |||
5570 | /* | ||
5571 | * Get the driver's phba structure from the dev_id and | ||
5572 | * assume the HBA is not interrupting. | ||
5573 | */ | ||
5574 | phba = (struct lpfc_hba *) dev_id; | ||
5575 | |||
5576 | if (unlikely(!phba)) | ||
5577 | return IRQ_NONE; | ||
5578 | |||
5579 | /* If the pci channel is offline, ignore all the interrupts. */ | ||
5580 | if (unlikely(pci_channel_offline(phba->pcidev))) | ||
5581 | return IRQ_NONE; | ||
5582 | |||
5583 | /* Update device level interrupt statistics */ | ||
5584 | phba->sli.slistat.sli_intr++; | ||
5585 | |||
5586 | /* Ignore all interrupts during initialization. */ | ||
5587 | if (unlikely(phba->link_state < LPFC_LINK_DOWN)) | ||
5588 | return IRQ_NONE; | ||
5589 | |||
5590 | spin_lock(&phba->hbalock); | ||
5591 | phba->ha_copy = readl(phba->HAregaddr); | ||
5592 | if (unlikely(!phba->ha_copy)) { | ||
5593 | spin_unlock(&phba->hbalock); | ||
5594 | return IRQ_NONE; | ||
5595 | } else if (phba->ha_copy & HA_ERATT) { | ||
5596 | if (phba->hba_flag & HBA_ERATT_HANDLED) | ||
5597 | /* ERATT polling has handled ERATT */ | ||
5598 | phba->ha_copy &= ~HA_ERATT; | ||
5599 | else | ||
5600 | /* Indicate interrupt handler handles ERATT */ | ||
5601 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
5602 | } | ||
5603 | |||
5604 | /* Clear attention sources except link and error attentions */ | ||
5605 | writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); | ||
5606 | readl(phba->HAregaddr); /* flush */ | ||
5607 | spin_unlock(&phba->hbalock); | ||
5608 | |||
5609 | /* | ||
5610 | * Invokes slow-path host attention interrupt handling as appropriate. | ||
5611 | */ | ||
5612 | |||
5613 | /* status of events with mailbox and link attention */ | ||
5614 | status1 = phba->ha_copy & (HA_MBATT | HA_LATT | HA_ERATT); | ||
5615 | |||
5616 | /* status of events with ELS ring */ | ||
5617 | status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); | ||
5618 | status2 >>= (4*LPFC_ELS_RING); | ||
5619 | |||
5620 | if (status1 || (status2 & HA_RXMASK)) | ||
5621 | sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id); | ||
5622 | else | ||
5623 | sp_irq_rc = IRQ_NONE; | ||
5624 | |||
5625 | /* | ||
5626 | * Invoke fast-path host attention interrupt handling as appropriate. | ||
5627 | */ | ||
5628 | |||
5629 | /* status of events with FCP ring */ | ||
5630 | status1 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); | ||
5631 | status1 >>= (4*LPFC_FCP_RING); | ||
5632 | |||
5633 | /* status of events with extra ring */ | ||
5634 | if (phba->cfg_multi_ring_support == 2) { | ||
5635 | status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); | ||
5636 | status2 >>= (4*LPFC_EXTRA_RING); | ||
5637 | } else | ||
5638 | status2 = 0; | ||
5639 | |||
5640 | if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK)) | ||
5641 | fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id); | ||
5642 | else | ||
5643 | fp_irq_rc = IRQ_NONE; | ||
5431 | 5644 | ||
5432 | } /* lpfc_intr_handler */ | 5645 | /* Return device-level interrupt handling status */ |
5646 | return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc; | ||
5647 | } /* lpfc_intr_handler */ | ||
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index ad24cacfbe10..1a62e57a6a2d 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h | |||
@@ -20,7 +20,9 @@ | |||
20 | 20 | ||
21 | #define LPFC_DRIVER_VERSION "8.2.7" | 21 | #define LPFC_DRIVER_VERSION "8.2.7" |
22 | 22 | ||
23 | #define LPFC_DRIVER_NAME "lpfc" | 23 | #define LPFC_DRIVER_NAME "lpfc" |
24 | #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" | ||
25 | #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" | ||
24 | 26 | ||
25 | #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ | 27 | #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ |
26 | LPFC_DRIVER_VERSION | 28 | LPFC_DRIVER_VERSION |