diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2012-08-22 07:55:08 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-24 04:11:08 -0400 |
commit | 6e7b429259fc0b7f2d9b1147466656b34d114815 (patch) | |
tree | b5bc8dc7e7e803f6589c9cdd4e71c8dc7a9932ab /drivers/scsi/qla4xxx/ql4_isr.c | |
parent | aec07caedbb769535e78adca30c851c977fd5741 (diff) |
[SCSI] qla4xxx: Added support for ISP83XX
Signed-off-by: Poornima Vonti <poornima.vonti@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_isr.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_isr.c | 202 |
1 files changed, 168 insertions, 34 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 55d366b14a51..cb78e9c16744 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c | |||
@@ -126,7 +126,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, | |||
126 | ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " | 126 | ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " |
127 | "handle=0x%0x, srb=%p\n", __func__, | 127 | "handle=0x%0x, srb=%p\n", __func__, |
128 | sts_entry->handle, srb); | 128 | sts_entry->handle, srb); |
129 | if (is_qla8022(ha)) | 129 | if (is_qla80XX(ha)) |
130 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); | 130 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); |
131 | else | 131 | else |
132 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | 132 | set_bit(DPC_RESET_HA, &ha->dpc_flags); |
@@ -594,6 +594,14 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
594 | { | 594 | { |
595 | int i; | 595 | int i; |
596 | uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; | 596 | uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; |
597 | __le32 __iomem *mailbox_out; | ||
598 | |||
599 | if (is_qla8032(ha)) | ||
600 | mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0]; | ||
601 | else if (is_qla8022(ha)) | ||
602 | mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0]; | ||
603 | else | ||
604 | mailbox_out = &ha->reg->mailbox[0]; | ||
597 | 605 | ||
598 | if ((mbox_status == MBOX_STS_BUSY) || | 606 | if ((mbox_status == MBOX_STS_BUSY) || |
599 | (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || | 607 | (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || |
@@ -606,9 +614,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
606 | * location and set mailbox command done flag | 614 | * location and set mailbox command done flag |
607 | */ | 615 | */ |
608 | for (i = 0; i < ha->mbox_status_count; i++) | 616 | for (i = 0; i < ha->mbox_status_count; i++) |
609 | ha->mbox_status[i] = is_qla8022(ha) | 617 | ha->mbox_status[i] = readl(&mailbox_out[i]); |
610 | ? readl(&ha->qla4_82xx_reg->mailbox_out[i]) | ||
611 | : readl(&ha->reg->mailbox[i]); | ||
612 | 618 | ||
613 | set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | 619 | set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); |
614 | 620 | ||
@@ -617,9 +623,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
617 | } | 623 | } |
618 | } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { | 624 | } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { |
619 | for (i = 0; i < MBOX_AEN_REG_COUNT; i++) | 625 | for (i = 0; i < MBOX_AEN_REG_COUNT; i++) |
620 | mbox_sts[i] = is_qla8022(ha) | 626 | mbox_sts[i] = readl(&mailbox_out[i]); |
621 | ? readl(&ha->qla4_82xx_reg->mailbox_out[i]) | ||
622 | : readl(&ha->reg->mailbox[i]); | ||
623 | 627 | ||
624 | /* Immediately process the AENs that don't require much work. | 628 | /* Immediately process the AENs that don't require much work. |
625 | * Only queue the database_changed AENs */ | 629 | * Only queue the database_changed AENs */ |
@@ -635,7 +639,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
635 | ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); | 639 | ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); |
636 | qla4xxx_dump_registers(ha); | 640 | qla4xxx_dump_registers(ha); |
637 | 641 | ||
638 | if (ql4xdontresethba) { | 642 | if ((is_qla8022(ha) && ql4xdontresethba) || |
643 | (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { | ||
639 | DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", | 644 | DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", |
640 | ha->host_no, __func__)); | 645 | ha->host_no, __func__)); |
641 | } else { | 646 | } else { |
@@ -651,7 +656,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
651 | case MBOX_ASTS_DHCP_LEASE_EXPIRED: | 656 | case MBOX_ASTS_DHCP_LEASE_EXPIRED: |
652 | DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " | 657 | DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " |
653 | "Reset HA\n", ha->host_no, mbox_status)); | 658 | "Reset HA\n", ha->host_no, mbox_status)); |
654 | if (is_qla8022(ha)) | 659 | if (is_qla80XX(ha)) |
655 | set_bit(DPC_RESET_HA_FW_CONTEXT, | 660 | set_bit(DPC_RESET_HA_FW_CONTEXT, |
656 | &ha->dpc_flags); | 661 | &ha->dpc_flags); |
657 | else | 662 | else |
@@ -716,7 +721,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
716 | set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); | 721 | set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); |
717 | else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && | 722 | else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && |
718 | (mbox_sts[2] == ACB_STATE_VALID)) { | 723 | (mbox_sts[2] == ACB_STATE_VALID)) { |
719 | if (is_qla8022(ha)) | 724 | if (is_qla80XX(ha)) |
720 | set_bit(DPC_RESET_HA_FW_CONTEXT, | 725 | set_bit(DPC_RESET_HA_FW_CONTEXT, |
721 | &ha->dpc_flags); | 726 | &ha->dpc_flags); |
722 | else | 727 | else |
@@ -815,6 +820,23 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
815 | } | 820 | } |
816 | } | 821 | } |
817 | 822 | ||
823 | void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha, | ||
824 | uint32_t intr_status) | ||
825 | { | ||
826 | /* Process mailbox/asynch event interrupt.*/ | ||
827 | if (intr_status) { | ||
828 | qla4xxx_isr_decode_mailbox(ha, | ||
829 | readl(&ha->qla4_83xx_reg->mailbox_out[0])); | ||
830 | /* clear the interrupt */ | ||
831 | writel(0, &ha->qla4_83xx_reg->risc_intr); | ||
832 | } else { | ||
833 | qla4xxx_process_response_queue(ha); | ||
834 | } | ||
835 | |||
836 | /* clear the interrupt */ | ||
837 | writel(0, &ha->qla4_83xx_reg->mb_int_mask); | ||
838 | } | ||
839 | |||
818 | /** | 840 | /** |
819 | * qla4_82xx_interrupt_service_routine - isr | 841 | * qla4_82xx_interrupt_service_routine - isr |
820 | * @ha: pointer to host adapter structure. | 842 | * @ha: pointer to host adapter structure. |
@@ -1045,6 +1067,59 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id) | |||
1045 | return IRQ_HANDLED; | 1067 | return IRQ_HANDLED; |
1046 | } | 1068 | } |
1047 | 1069 | ||
1070 | #define LEG_INT_PTR_B31 (1 << 31) | ||
1071 | #define LEG_INT_PTR_B30 (1 << 30) | ||
1072 | #define PF_BITS_MASK (0xF << 16) | ||
1073 | |||
1074 | /** | ||
1075 | * qla4_83xx_intr_handler - hardware interrupt handler. | ||
1076 | * @irq: Unused | ||
1077 | * @dev_id: Pointer to host adapter structure | ||
1078 | **/ | ||
1079 | irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id) | ||
1080 | { | ||
1081 | struct scsi_qla_host *ha = dev_id; | ||
1082 | uint32_t leg_int_ptr = 0; | ||
1083 | unsigned long flags = 0; | ||
1084 | |||
1085 | ha->isr_count++; | ||
1086 | leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); | ||
1087 | |||
1088 | /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */ | ||
1089 | if (!(leg_int_ptr & LEG_INT_PTR_B31)) { | ||
1090 | ql4_printk(KERN_ERR, ha, | ||
1091 | "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n", | ||
1092 | __func__); | ||
1093 | return IRQ_NONE; | ||
1094 | } | ||
1095 | |||
1096 | /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */ | ||
1097 | if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) { | ||
1098 | ql4_printk(KERN_ERR, ha, | ||
1099 | "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n", | ||
1100 | __func__, (leg_int_ptr & PF_BITS_MASK), ha->pf_bit); | ||
1101 | return IRQ_NONE; | ||
1102 | } | ||
1103 | |||
1104 | /* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger | ||
1105 | * Control register and poll till Legacy Interrupt Pointer register | ||
1106 | * bit30 is 0. | ||
1107 | */ | ||
1108 | writel(0, &ha->qla4_83xx_reg->leg_int_trig); | ||
1109 | do { | ||
1110 | leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); | ||
1111 | if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) | ||
1112 | break; | ||
1113 | } while (leg_int_ptr & LEG_INT_PTR_B30); | ||
1114 | |||
1115 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1116 | leg_int_ptr = readl(&ha->qla4_83xx_reg->risc_intr); | ||
1117 | ha->isp_ops->interrupt_service_routine(ha, leg_int_ptr); | ||
1118 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1119 | |||
1120 | return IRQ_HANDLED; | ||
1121 | } | ||
1122 | |||
1048 | irqreturn_t | 1123 | irqreturn_t |
1049 | qla4_8xxx_msi_handler(int irq, void *dev_id) | 1124 | qla4_8xxx_msi_handler(int irq, void *dev_id) |
1050 | { | 1125 | { |
@@ -1068,6 +1143,37 @@ qla4_8xxx_msi_handler(int irq, void *dev_id) | |||
1068 | return qla4_8xxx_default_intr_handler(irq, dev_id); | 1143 | return qla4_8xxx_default_intr_handler(irq, dev_id); |
1069 | } | 1144 | } |
1070 | 1145 | ||
1146 | static irqreturn_t qla4_83xx_mailbox_intr_handler(int irq, void *dev_id) | ||
1147 | { | ||
1148 | struct scsi_qla_host *ha = dev_id; | ||
1149 | unsigned long flags; | ||
1150 | uint32_t ival = 0; | ||
1151 | |||
1152 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1153 | |||
1154 | ival = readl(&ha->qla4_83xx_reg->risc_intr); | ||
1155 | if (ival == 0) { | ||
1156 | ql4_printk(KERN_INFO, ha, | ||
1157 | "%s: It is a spurious mailbox interrupt!\n", | ||
1158 | __func__); | ||
1159 | ival = readl(&ha->qla4_83xx_reg->mb_int_mask); | ||
1160 | ival &= ~INT_MASK_FW_MB; | ||
1161 | writel(ival, &ha->qla4_83xx_reg->mb_int_mask); | ||
1162 | goto exit; | ||
1163 | } | ||
1164 | |||
1165 | qla4xxx_isr_decode_mailbox(ha, | ||
1166 | readl(&ha->qla4_83xx_reg->mailbox_out[0])); | ||
1167 | writel(0, &ha->qla4_83xx_reg->risc_intr); | ||
1168 | ival = readl(&ha->qla4_83xx_reg->mb_int_mask); | ||
1169 | ival &= ~INT_MASK_FW_MB; | ||
1170 | writel(ival, &ha->qla4_83xx_reg->mb_int_mask); | ||
1171 | ha->isr_count++; | ||
1172 | exit: | ||
1173 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1174 | return IRQ_HANDLED; | ||
1175 | } | ||
1176 | |||
1071 | /** | 1177 | /** |
1072 | * qla4_8xxx_default_intr_handler - hardware interrupt handler. | 1178 | * qla4_8xxx_default_intr_handler - hardware interrupt handler. |
1073 | * @irq: Unused | 1179 | * @irq: Unused |
@@ -1084,29 +1190,32 @@ qla4_8xxx_default_intr_handler(int irq, void *dev_id) | |||
1084 | uint32_t intr_status; | 1190 | uint32_t intr_status; |
1085 | uint8_t reqs_count = 0; | 1191 | uint8_t reqs_count = 0; |
1086 | 1192 | ||
1087 | spin_lock_irqsave(&ha->hardware_lock, flags); | 1193 | if (is_qla8032(ha)) { |
1088 | while (1) { | 1194 | qla4_83xx_mailbox_intr_handler(irq, dev_id); |
1089 | if (!(readl(&ha->qla4_82xx_reg->host_int) & | 1195 | } else { |
1090 | ISRX_82XX_RISC_INT)) { | 1196 | spin_lock_irqsave(&ha->hardware_lock, flags); |
1091 | qla4_82xx_spurious_interrupt(ha, reqs_count); | 1197 | while (1) { |
1092 | break; | 1198 | if (!(readl(&ha->qla4_82xx_reg->host_int) & |
1093 | } | 1199 | ISRX_82XX_RISC_INT)) { |
1200 | qla4_82xx_spurious_interrupt(ha, reqs_count); | ||
1201 | break; | ||
1202 | } | ||
1094 | 1203 | ||
1095 | intr_status = readl(&ha->qla4_82xx_reg->host_status); | 1204 | intr_status = readl(&ha->qla4_82xx_reg->host_status); |
1096 | if ((intr_status & | 1205 | if ((intr_status & |
1097 | (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { | 1206 | (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { |
1098 | qla4_82xx_spurious_interrupt(ha, reqs_count); | 1207 | qla4_82xx_spurious_interrupt(ha, reqs_count); |
1099 | break; | 1208 | break; |
1100 | } | 1209 | } |
1101 | 1210 | ||
1102 | ha->isp_ops->interrupt_service_routine(ha, intr_status); | 1211 | ha->isp_ops->interrupt_service_routine(ha, intr_status); |
1103 | 1212 | ||
1104 | if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) | 1213 | if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) |
1105 | break; | 1214 | break; |
1215 | } | ||
1216 | ha->isr_count++; | ||
1217 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1106 | } | 1218 | } |
1107 | |||
1108 | ha->isr_count++; | ||
1109 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1110 | return IRQ_HANDLED; | 1219 | return IRQ_HANDLED; |
1111 | } | 1220 | } |
1112 | 1221 | ||
@@ -1115,13 +1224,25 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id) | |||
1115 | { | 1224 | { |
1116 | struct scsi_qla_host *ha = dev_id; | 1225 | struct scsi_qla_host *ha = dev_id; |
1117 | unsigned long flags; | 1226 | unsigned long flags; |
1227 | uint32_t ival = 0; | ||
1118 | 1228 | ||
1119 | spin_lock_irqsave(&ha->hardware_lock, flags); | 1229 | spin_lock_irqsave(&ha->hardware_lock, flags); |
1120 | qla4xxx_process_response_queue(ha); | 1230 | if (is_qla8032(ha)) { |
1121 | writel(0, &ha->qla4_82xx_reg->host_int); | 1231 | ival = readl(&ha->qla4_83xx_reg->iocb_int_mask); |
1122 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 1232 | if (ival == 0) { |
1123 | 1233 | ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n", | |
1234 | __func__); | ||
1235 | goto exit_msix_rsp_q; | ||
1236 | } | ||
1237 | qla4xxx_process_response_queue(ha); | ||
1238 | writel(0, &ha->qla4_83xx_reg->iocb_int_mask); | ||
1239 | } else { | ||
1240 | qla4xxx_process_response_queue(ha); | ||
1241 | writel(0, &ha->qla4_82xx_reg->host_int); | ||
1242 | } | ||
1124 | ha->isr_count++; | 1243 | ha->isr_count++; |
1244 | exit_msix_rsp_q: | ||
1245 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1125 | return IRQ_HANDLED; | 1246 | return IRQ_HANDLED; |
1126 | } | 1247 | } |
1127 | 1248 | ||
@@ -1196,8 +1317,15 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha) | |||
1196 | if (is_qla40XX(ha)) | 1317 | if (is_qla40XX(ha)) |
1197 | goto try_intx; | 1318 | goto try_intx; |
1198 | 1319 | ||
1199 | if (ql4xenablemsix == 2) | 1320 | if (ql4xenablemsix == 2) { |
1321 | /* Note: MSI Interrupts not supported for ISP8324 */ | ||
1322 | if (is_qla8032(ha)) { | ||
1323 | ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP8324, Falling back-to INTx mode\n", | ||
1324 | __func__); | ||
1325 | goto try_intx; | ||
1326 | } | ||
1200 | goto try_msi; | 1327 | goto try_msi; |
1328 | } | ||
1201 | 1329 | ||
1202 | if (ql4xenablemsix == 0 || ql4xenablemsix != 1) | 1330 | if (ql4xenablemsix == 0 || ql4xenablemsix != 1) |
1203 | goto try_intx; | 1331 | goto try_intx; |
@@ -1208,6 +1336,12 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha) | |||
1208 | DEBUG2(ql4_printk(KERN_INFO, ha, | 1336 | DEBUG2(ql4_printk(KERN_INFO, ha, |
1209 | "MSI-X: Enabled (0x%X).\n", ha->revision_id)); | 1337 | "MSI-X: Enabled (0x%X).\n", ha->revision_id)); |
1210 | goto irq_attached; | 1338 | goto irq_attached; |
1339 | } else { | ||
1340 | if (is_qla8032(ha)) { | ||
1341 | ql4_printk(KERN_INFO, ha, "%s: ISP8324: MSI-X: Falling back-to INTx mode. ret = %d\n", | ||
1342 | __func__, ret); | ||
1343 | goto try_intx; | ||
1344 | } | ||
1211 | } | 1345 | } |
1212 | 1346 | ||
1213 | ql4_printk(KERN_WARNING, ha, | 1347 | ql4_printk(KERN_WARNING, ha, |