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 /drivers/scsi/lpfc/lpfc_sli.c | |
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>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 401 |
1 files changed, 308 insertions, 93 deletions
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 */ | ||