diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 448 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 46 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_config.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 29 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 3 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 2 |
6 files changed, 405 insertions, 124 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 83035bd1c489..81209ca87274 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
| @@ -42,7 +42,6 @@ | |||
| 42 | * USA. | 42 | * USA. |
| 43 | */ | 43 | */ |
| 44 | 44 | ||
| 45 | #include <linux/version.h> | ||
| 46 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
| 47 | #include <linux/module.h> | 46 | #include <linux/module.h> |
| 48 | #include <linux/errno.h> | 47 | #include <linux/errno.h> |
| @@ -834,25 +833,31 @@ union reply_descriptor { | |||
| 834 | static irqreturn_t | 833 | static irqreturn_t |
| 835 | _base_interrupt(int irq, void *bus_id) | 834 | _base_interrupt(int irq, void *bus_id) |
| 836 | { | 835 | { |
| 836 | struct adapter_reply_queue *reply_q = bus_id; | ||
| 837 | union reply_descriptor rd; | 837 | union reply_descriptor rd; |
| 838 | u32 completed_cmds; | 838 | u32 completed_cmds; |
| 839 | u8 request_desript_type; | 839 | u8 request_desript_type; |
| 840 | u16 smid; | 840 | u16 smid; |
| 841 | u8 cb_idx; | 841 | u8 cb_idx; |
| 842 | u32 reply; | 842 | u32 reply; |
| 843 | u8 msix_index; | 843 | u8 msix_index = reply_q->msix_index; |
| 844 | struct MPT2SAS_ADAPTER *ioc = bus_id; | 844 | struct MPT2SAS_ADAPTER *ioc = reply_q->ioc; |
| 845 | Mpi2ReplyDescriptorsUnion_t *rpf; | 845 | Mpi2ReplyDescriptorsUnion_t *rpf; |
| 846 | u8 rc; | 846 | u8 rc; |
| 847 | 847 | ||
| 848 | if (ioc->mask_interrupts) | 848 | if (ioc->mask_interrupts) |
| 849 | return IRQ_NONE; | 849 | return IRQ_NONE; |
| 850 | 850 | ||
| 851 | rpf = &ioc->reply_post_free[ioc->reply_post_host_index]; | 851 | if (!atomic_add_unless(&reply_q->busy, 1, 1)) |
| 852 | return IRQ_NONE; | ||
| 853 | |||
| 854 | rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; | ||
| 852 | request_desript_type = rpf->Default.ReplyFlags | 855 | request_desript_type = rpf->Default.ReplyFlags |
| 853 | & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; | 856 | & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; |
| 854 | if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) | 857 | if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { |
| 858 | atomic_dec(&reply_q->busy); | ||
| 855 | return IRQ_NONE; | 859 | return IRQ_NONE; |
| 860 | } | ||
| 856 | 861 | ||
| 857 | completed_cmds = 0; | 862 | completed_cmds = 0; |
| 858 | cb_idx = 0xFF; | 863 | cb_idx = 0xFF; |
| @@ -861,9 +866,7 @@ _base_interrupt(int irq, void *bus_id) | |||
| 861 | if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) | 866 | if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) |
| 862 | goto out; | 867 | goto out; |
| 863 | reply = 0; | 868 | reply = 0; |
| 864 | cb_idx = 0xFF; | ||
| 865 | smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); | 869 | smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); |
| 866 | msix_index = rpf->Default.MSIxIndex; | ||
| 867 | if (request_desript_type == | 870 | if (request_desript_type == |
| 868 | MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { | 871 | MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { |
| 869 | reply = le32_to_cpu | 872 | reply = le32_to_cpu |
| @@ -907,32 +910,86 @@ _base_interrupt(int irq, void *bus_id) | |||
| 907 | next: | 910 | next: |
| 908 | 911 | ||
| 909 | rpf->Words = cpu_to_le64(ULLONG_MAX); | 912 | rpf->Words = cpu_to_le64(ULLONG_MAX); |
| 910 | ioc->reply_post_host_index = (ioc->reply_post_host_index == | 913 | reply_q->reply_post_host_index = |
| 914 | (reply_q->reply_post_host_index == | ||
| 911 | (ioc->reply_post_queue_depth - 1)) ? 0 : | 915 | (ioc->reply_post_queue_depth - 1)) ? 0 : |
| 912 | ioc->reply_post_host_index + 1; | 916 | reply_q->reply_post_host_index + 1; |
| 913 | request_desript_type = | 917 | request_desript_type = |
| 914 | ioc->reply_post_free[ioc->reply_post_host_index].Default. | 918 | reply_q->reply_post_free[reply_q->reply_post_host_index]. |
| 915 | ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; | 919 | Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; |
| 916 | completed_cmds++; | 920 | completed_cmds++; |
| 917 | if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) | 921 | if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) |
| 918 | goto out; | 922 | goto out; |
| 919 | if (!ioc->reply_post_host_index) | 923 | if (!reply_q->reply_post_host_index) |
| 920 | rpf = ioc->reply_post_free; | 924 | rpf = reply_q->reply_post_free; |
| 921 | else | 925 | else |
| 922 | rpf++; | 926 | rpf++; |
| 923 | } while (1); | 927 | } while (1); |
| 924 | 928 | ||
| 925 | out: | 929 | out: |
| 926 | 930 | ||
| 927 | if (!completed_cmds) | 931 | if (!completed_cmds) { |
| 932 | atomic_dec(&reply_q->busy); | ||
| 928 | return IRQ_NONE; | 933 | return IRQ_NONE; |
| 929 | 934 | } | |
| 930 | wmb(); | 935 | wmb(); |
| 931 | writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex); | 936 | if (ioc->is_warpdrive) { |
| 937 | writel(reply_q->reply_post_host_index, | ||
| 938 | ioc->reply_post_host_index[msix_index]); | ||
| 939 | atomic_dec(&reply_q->busy); | ||
| 940 | return IRQ_HANDLED; | ||
| 941 | } | ||
| 942 | writel(reply_q->reply_post_host_index | (msix_index << | ||
| 943 | MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); | ||
| 944 | atomic_dec(&reply_q->busy); | ||
| 932 | return IRQ_HANDLED; | 945 | return IRQ_HANDLED; |
| 933 | } | 946 | } |
| 934 | 947 | ||
| 935 | /** | 948 | /** |
| 949 | * _base_is_controller_msix_enabled - is controller support muli-reply queues | ||
| 950 | * @ioc: per adapter object | ||
| 951 | * | ||
| 952 | */ | ||
| 953 | static inline int | ||
| 954 | _base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc) | ||
| 955 | { | ||
| 956 | return (ioc->facts.IOCCapabilities & | ||
| 957 | MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; | ||
| 958 | } | ||
| 959 | |||
| 960 | /** | ||
| 961 | * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues | ||
| 962 | * @ioc: per adapter object | ||
| 963 | * Context: ISR conext | ||
| 964 | * | ||
| 965 | * Called when a Task Management request has completed. We want | ||
| 966 | * to flush the other reply queues so all the outstanding IO has been | ||
| 967 | * completed back to OS before we process the TM completetion. | ||
| 968 | * | ||
| 969 | * Return nothing. | ||
| 970 | */ | ||
| 971 | void | ||
| 972 | mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc) | ||
| 973 | { | ||
| 974 | struct adapter_reply_queue *reply_q; | ||
| 975 | |||
| 976 | /* If MSIX capability is turned off | ||
| 977 | * then multi-queues are not enabled | ||
| 978 | */ | ||
| 979 | if (!_base_is_controller_msix_enabled(ioc)) | ||
| 980 | return; | ||
| 981 | |||
| 982 | list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { | ||
| 983 | if (ioc->shost_recovery) | ||
| 984 | return; | ||
| 985 | /* TMs are on msix_index == 0 */ | ||
| 986 | if (reply_q->msix_index == 0) | ||
| 987 | continue; | ||
| 988 | _base_interrupt(reply_q->vector, (void *)reply_q); | ||
| 989 | } | ||
| 990 | } | ||
| 991 | |||
| 992 | /** | ||
| 936 | * mpt2sas_base_release_callback_handler - clear interrupt callback handler | 993 | * mpt2sas_base_release_callback_handler - clear interrupt callback handler |
| 937 | * @cb_idx: callback index | 994 | * @cb_idx: callback index |
| 938 | * | 995 | * |
| @@ -1082,74 +1139,171 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev) | |||
| 1082 | } | 1139 | } |
| 1083 | 1140 | ||
| 1084 | /** | 1141 | /** |
| 1085 | * _base_save_msix_table - backup msix vector table | 1142 | * _base_check_enable_msix - checks MSIX capabable. |
| 1086 | * @ioc: per adapter object | 1143 | * @ioc: per adapter object |
| 1087 | * | 1144 | * |
| 1088 | * This address an errata where diag reset clears out the table | 1145 | * Check to see if card is capable of MSIX, and set number |
| 1146 | * of available msix vectors | ||
| 1089 | */ | 1147 | */ |
| 1090 | static void | 1148 | static int |
| 1091 | _base_save_msix_table(struct MPT2SAS_ADAPTER *ioc) | 1149 | _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) |
| 1092 | { | 1150 | { |
| 1093 | int i; | 1151 | int base; |
| 1152 | u16 message_control; | ||
| 1094 | 1153 | ||
| 1095 | if (!ioc->msix_enable || ioc->msix_table_backup == NULL) | ||
| 1096 | return; | ||
| 1097 | 1154 | ||
| 1098 | for (i = 0; i < ioc->msix_vector_count; i++) | 1155 | base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); |
| 1099 | ioc->msix_table_backup[i] = ioc->msix_table[i]; | 1156 | if (!base) { |
| 1157 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " | ||
| 1158 | "supported\n", ioc->name)); | ||
| 1159 | return -EINVAL; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | /* get msix vector count */ | ||
| 1163 | /* NUMA_IO not supported for older controllers */ | ||
| 1164 | if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || | ||
| 1165 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || | ||
| 1166 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || | ||
| 1167 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || | ||
| 1168 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || | ||
| 1169 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || | ||
| 1170 | ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) | ||
| 1171 | ioc->msix_vector_count = 1; | ||
| 1172 | else { | ||
| 1173 | pci_read_config_word(ioc->pdev, base + 2, &message_control); | ||
| 1174 | ioc->msix_vector_count = (message_control & 0x3FF) + 1; | ||
| 1175 | } | ||
| 1176 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " | ||
| 1177 | "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); | ||
| 1178 | |||
| 1179 | return 0; | ||
| 1100 | } | 1180 | } |
| 1101 | 1181 | ||
| 1102 | /** | 1182 | /** |
| 1103 | * _base_restore_msix_table - this restores the msix vector table | 1183 | * _base_free_irq - free irq |
| 1104 | * @ioc: per adapter object | 1184 | * @ioc: per adapter object |
| 1105 | * | 1185 | * |
| 1186 | * Freeing respective reply_queue from the list. | ||
| 1106 | */ | 1187 | */ |
| 1107 | static void | 1188 | static void |
| 1108 | _base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc) | 1189 | _base_free_irq(struct MPT2SAS_ADAPTER *ioc) |
| 1109 | { | 1190 | { |
| 1110 | int i; | 1191 | struct adapter_reply_queue *reply_q, *next; |
| 1111 | 1192 | ||
| 1112 | if (!ioc->msix_enable || ioc->msix_table_backup == NULL) | 1193 | if (list_empty(&ioc->reply_queue_list)) |
| 1113 | return; | 1194 | return; |
| 1114 | 1195 | ||
| 1115 | for (i = 0; i < ioc->msix_vector_count; i++) | 1196 | list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { |
| 1116 | ioc->msix_table[i] = ioc->msix_table_backup[i]; | 1197 | list_del(&reply_q->list); |
| 1198 | synchronize_irq(reply_q->vector); | ||
| 1199 | free_irq(reply_q->vector, reply_q); | ||
| 1200 | kfree(reply_q); | ||
| 1201 | } | ||
| 1117 | } | 1202 | } |
| 1118 | 1203 | ||
| 1119 | /** | 1204 | /** |
| 1120 | * _base_check_enable_msix - checks MSIX capabable. | 1205 | * _base_request_irq - request irq |
| 1121 | * @ioc: per adapter object | 1206 | * @ioc: per adapter object |
| 1207 | * @index: msix index into vector table | ||
| 1208 | * @vector: irq vector | ||
| 1122 | * | 1209 | * |
| 1123 | * Check to see if card is capable of MSIX, and set number | 1210 | * Inserting respective reply_queue into the list. |
| 1124 | * of available msix vectors | ||
| 1125 | */ | 1211 | */ |
| 1126 | static int | 1212 | static int |
| 1127 | _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) | 1213 | _base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector) |
| 1128 | { | 1214 | { |
| 1129 | int base; | 1215 | struct adapter_reply_queue *reply_q; |
| 1130 | u16 message_control; | 1216 | int r; |
| 1131 | u32 msix_table_offset; | ||
| 1132 | 1217 | ||
| 1133 | base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); | 1218 | reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); |
| 1134 | if (!base) { | 1219 | if (!reply_q) { |
| 1135 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " | 1220 | printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n", |
| 1136 | "supported\n", ioc->name)); | 1221 | ioc->name, (int)sizeof(struct adapter_reply_queue)); |
| 1137 | return -EINVAL; | 1222 | return -ENOMEM; |
| 1223 | } | ||
| 1224 | reply_q->ioc = ioc; | ||
| 1225 | reply_q->msix_index = index; | ||
| 1226 | reply_q->vector = vector; | ||
| 1227 | atomic_set(&reply_q->busy, 0); | ||
| 1228 | if (ioc->msix_enable) | ||
| 1229 | snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", | ||
| 1230 | MPT2SAS_DRIVER_NAME, ioc->id, index); | ||
| 1231 | else | ||
| 1232 | snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", | ||
| 1233 | MPT2SAS_DRIVER_NAME, ioc->id); | ||
| 1234 | r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, | ||
| 1235 | reply_q); | ||
| 1236 | if (r) { | ||
| 1237 | printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", | ||
| 1238 | reply_q->name, vector); | ||
| 1239 | kfree(reply_q); | ||
| 1240 | return -EBUSY; | ||
| 1138 | } | 1241 | } |
| 1139 | 1242 | ||
| 1140 | /* get msix vector count */ | 1243 | INIT_LIST_HEAD(&reply_q->list); |
| 1141 | pci_read_config_word(ioc->pdev, base + 2, &message_control); | 1244 | list_add_tail(&reply_q->list, &ioc->reply_queue_list); |
| 1142 | ioc->msix_vector_count = (message_control & 0x3FF) + 1; | 1245 | return 0; |
| 1246 | } | ||
| 1143 | 1247 | ||
| 1144 | /* get msix table */ | 1248 | /** |
| 1145 | pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset); | 1249 | * _base_assign_reply_queues - assigning msix index for each cpu |
| 1146 | msix_table_offset &= 0xFFFFFFF8; | 1250 | * @ioc: per adapter object |
| 1147 | ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset); | 1251 | * |
| 1252 | * The enduser would need to set the affinity via /proc/irq/#/smp_affinity | ||
| 1253 | * | ||
| 1254 | * It would nice if we could call irq_set_affinity, however it is not | ||
| 1255 | * an exported symbol | ||
| 1256 | */ | ||
| 1257 | static void | ||
| 1258 | _base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) | ||
| 1259 | { | ||
| 1260 | struct adapter_reply_queue *reply_q; | ||
| 1261 | int cpu_id; | ||
| 1262 | int cpu_grouping, loop, grouping, grouping_mod; | ||
| 1148 | 1263 | ||
| 1149 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " | 1264 | if (!_base_is_controller_msix_enabled(ioc)) |
| 1150 | "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name, | 1265 | return; |
| 1151 | ioc->msix_vector_count, msix_table_offset, ioc->msix_table)); | 1266 | |
| 1152 | return 0; | 1267 | memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); |
| 1268 | /* when there are more cpus than available msix vectors, | ||
| 1269 | * then group cpus togeather on same irq | ||
| 1270 | */ | ||
| 1271 | if (ioc->cpu_count > ioc->msix_vector_count) { | ||
| 1272 | grouping = ioc->cpu_count / ioc->msix_vector_count; | ||
| 1273 | grouping_mod = ioc->cpu_count % ioc->msix_vector_count; | ||
| 1274 | if (grouping < 2 || (grouping == 2 && !grouping_mod)) | ||
| 1275 | cpu_grouping = 2; | ||
| 1276 | else if (grouping < 4 || (grouping == 4 && !grouping_mod)) | ||
| 1277 | cpu_grouping = 4; | ||
| 1278 | else if (grouping < 8 || (grouping == 8 && !grouping_mod)) | ||
| 1279 | cpu_grouping = 8; | ||
| 1280 | else | ||
| 1281 | cpu_grouping = 16; | ||
| 1282 | } else | ||
| 1283 | cpu_grouping = 0; | ||
| 1284 | |||
| 1285 | loop = 0; | ||
| 1286 | reply_q = list_entry(ioc->reply_queue_list.next, | ||
| 1287 | struct adapter_reply_queue, list); | ||
| 1288 | for_each_online_cpu(cpu_id) { | ||
| 1289 | if (!cpu_grouping) { | ||
| 1290 | ioc->cpu_msix_table[cpu_id] = reply_q->msix_index; | ||
| 1291 | reply_q = list_entry(reply_q->list.next, | ||
| 1292 | struct adapter_reply_queue, list); | ||
| 1293 | } else { | ||
| 1294 | if (loop < cpu_grouping) { | ||
| 1295 | ioc->cpu_msix_table[cpu_id] = | ||
| 1296 | reply_q->msix_index; | ||
| 1297 | loop++; | ||
| 1298 | } else { | ||
| 1299 | reply_q = list_entry(reply_q->list.next, | ||
| 1300 | struct adapter_reply_queue, list); | ||
| 1301 | ioc->cpu_msix_table[cpu_id] = | ||
| 1302 | reply_q->msix_index; | ||
| 1303 | loop = 1; | ||
| 1304 | } | ||
| 1305 | } | ||
| 1306 | } | ||
| 1153 | } | 1307 | } |
| 1154 | 1308 | ||
| 1155 | /** | 1309 | /** |
| @@ -1162,8 +1316,6 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc) | |||
| 1162 | { | 1316 | { |
| 1163 | if (ioc->msix_enable) { | 1317 | if (ioc->msix_enable) { |
| 1164 | pci_disable_msix(ioc->pdev); | 1318 | pci_disable_msix(ioc->pdev); |
| 1165 | kfree(ioc->msix_table_backup); | ||
| 1166 | ioc->msix_table_backup = NULL; | ||
| 1167 | ioc->msix_enable = 0; | 1319 | ioc->msix_enable = 0; |
| 1168 | } | 1320 | } |
| 1169 | } | 1321 | } |
| @@ -1176,10 +1328,13 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc) | |||
| 1176 | static int | 1328 | static int |
| 1177 | _base_enable_msix(struct MPT2SAS_ADAPTER *ioc) | 1329 | _base_enable_msix(struct MPT2SAS_ADAPTER *ioc) |
| 1178 | { | 1330 | { |
| 1179 | struct msix_entry entries; | 1331 | struct msix_entry *entries, *a; |
| 1180 | int r; | 1332 | int r; |
| 1333 | int i; | ||
| 1181 | u8 try_msix = 0; | 1334 | u8 try_msix = 0; |
| 1182 | 1335 | ||
| 1336 | INIT_LIST_HEAD(&ioc->reply_queue_list); | ||
| 1337 | |||
| 1183 | if (msix_disable == -1 || msix_disable == 0) | 1338 | if (msix_disable == -1 || msix_disable == 0) |
| 1184 | try_msix = 1; | 1339 | try_msix = 1; |
| 1185 | 1340 | ||
| @@ -1189,51 +1344,48 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc) | |||
| 1189 | if (_base_check_enable_msix(ioc) != 0) | 1344 | if (_base_check_enable_msix(ioc) != 0) |
| 1190 | goto try_ioapic; | 1345 | goto try_ioapic; |
| 1191 | 1346 | ||
| 1192 | ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, | 1347 | ioc->reply_queue_count = min_t(u8, ioc->cpu_count, |
| 1193 | sizeof(u32), GFP_KERNEL); | 1348 | ioc->msix_vector_count); |
| 1194 | if (!ioc->msix_table_backup) { | 1349 | |
| 1195 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " | 1350 | entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), |
| 1196 | "msix_table_backup failed!!!\n", ioc->name)); | 1351 | GFP_KERNEL); |
| 1352 | if (!entries) { | ||
| 1353 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc " | ||
| 1354 | "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__, | ||
| 1355 | __LINE__, __func__)); | ||
| 1197 | goto try_ioapic; | 1356 | goto try_ioapic; |
| 1198 | } | 1357 | } |
| 1199 | 1358 | ||
| 1200 | memset(&entries, 0, sizeof(struct msix_entry)); | 1359 | for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) |
| 1201 | r = pci_enable_msix(ioc->pdev, &entries, 1); | 1360 | a->entry = i; |
| 1361 | |||
| 1362 | r = pci_enable_msix(ioc->pdev, entries, ioc->reply_queue_count); | ||
| 1202 | if (r) { | 1363 | if (r) { |
| 1203 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix " | 1364 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix " |
| 1204 | "failed (r=%d) !!!\n", ioc->name, r)); | 1365 | "failed (r=%d) !!!\n", ioc->name, r)); |
| 1366 | kfree(entries); | ||
| 1205 | goto try_ioapic; | 1367 | goto try_ioapic; |
| 1206 | } | 1368 | } |
| 1207 | 1369 | ||
| 1208 | r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED, | 1370 | ioc->msix_enable = 1; |
| 1209 | ioc->name, ioc); | 1371 | for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { |
| 1210 | if (r) { | 1372 | r = _base_request_irq(ioc, i, a->vector); |
| 1211 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate " | 1373 | if (r) { |
| 1212 | "interrupt %d !!!\n", ioc->name, entries.vector)); | 1374 | _base_free_irq(ioc); |
| 1213 | pci_disable_msix(ioc->pdev); | 1375 | _base_disable_msix(ioc); |
| 1214 | goto try_ioapic; | 1376 | kfree(entries); |
| 1377 | goto try_ioapic; | ||
| 1378 | } | ||
| 1215 | } | 1379 | } |
| 1216 | 1380 | ||
| 1217 | ioc->pci_irq = entries.vector; | 1381 | kfree(entries); |
| 1218 | ioc->msix_enable = 1; | ||
| 1219 | return 0; | 1382 | return 0; |
| 1220 | 1383 | ||
| 1221 | /* failback to io_apic interrupt routing */ | 1384 | /* failback to io_apic interrupt routing */ |
| 1222 | try_ioapic: | 1385 | try_ioapic: |
| 1223 | 1386 | ||
| 1224 | r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED, | 1387 | r = _base_request_irq(ioc, 0, ioc->pdev->irq); |
| 1225 | ioc->name, ioc); | ||
| 1226 | if (r) { | ||
| 1227 | printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", | ||
| 1228 | ioc->name, ioc->pdev->irq); | ||
| 1229 | r = -EBUSY; | ||
| 1230 | goto out_fail; | ||
| 1231 | } | ||
| 1232 | 1388 | ||
| 1233 | ioc->pci_irq = ioc->pdev->irq; | ||
| 1234 | return 0; | ||
| 1235 | |||
| 1236 | out_fail: | ||
| 1237 | return r; | 1389 | return r; |
| 1238 | } | 1390 | } |
| 1239 | 1391 | ||
| @@ -1252,6 +1404,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
| 1252 | int i, r = 0; | 1404 | int i, r = 0; |
| 1253 | u64 pio_chip = 0; | 1405 | u64 pio_chip = 0; |
| 1254 | u64 chip_phys = 0; | 1406 | u64 chip_phys = 0; |
| 1407 | struct adapter_reply_queue *reply_q; | ||
| 1255 | 1408 | ||
| 1256 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", | 1409 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", |
| 1257 | ioc->name, __func__)); | 1410 | ioc->name, __func__)); |
| @@ -1314,9 +1467,11 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
| 1314 | if (r) | 1467 | if (r) |
| 1315 | goto out_fail; | 1468 | goto out_fail; |
| 1316 | 1469 | ||
| 1317 | printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", | 1470 | list_for_each_entry(reply_q, &ioc->reply_queue_list, list) |
| 1318 | ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : | 1471 | printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", |
| 1319 | "IO-APIC enabled"), ioc->pci_irq); | 1472 | reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : |
| 1473 | "IO-APIC enabled"), reply_q->vector); | ||
| 1474 | |||
| 1320 | printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", | 1475 | printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", |
| 1321 | ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); | 1476 | ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); |
| 1322 | printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", | 1477 | printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", |
| @@ -1331,7 +1486,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
| 1331 | if (ioc->chip_phys) | 1486 | if (ioc->chip_phys) |
| 1332 | iounmap(ioc->chip); | 1487 | iounmap(ioc->chip); |
| 1333 | ioc->chip_phys = 0; | 1488 | ioc->chip_phys = 0; |
| 1334 | ioc->pci_irq = -1; | ||
| 1335 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 1489 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
| 1336 | pci_disable_pcie_error_reporting(pdev); | 1490 | pci_disable_pcie_error_reporting(pdev); |
| 1337 | pci_disable_device(pdev); | 1491 | pci_disable_device(pdev); |
| @@ -1578,6 +1732,12 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr, | |||
| 1578 | } | 1732 | } |
| 1579 | #endif | 1733 | #endif |
| 1580 | 1734 | ||
| 1735 | static inline u8 | ||
| 1736 | _base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) | ||
| 1737 | { | ||
| 1738 | return ioc->cpu_msix_table[smp_processor_id()]; | ||
| 1739 | } | ||
| 1740 | |||
| 1581 | /** | 1741 | /** |
| 1582 | * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware | 1742 | * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware |
| 1583 | * @ioc: per adapter object | 1743 | * @ioc: per adapter object |
| @@ -1594,7 +1754,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) | |||
| 1594 | 1754 | ||
| 1595 | 1755 | ||
| 1596 | descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; | 1756 | descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; |
| 1597 | descriptor.SCSIIO.MSIxIndex = 0; /* TODO */ | 1757 | descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); |
| 1598 | descriptor.SCSIIO.SMID = cpu_to_le16(smid); | 1758 | descriptor.SCSIIO.SMID = cpu_to_le16(smid); |
| 1599 | descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); | 1759 | descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); |
| 1600 | descriptor.SCSIIO.LMID = 0; | 1760 | descriptor.SCSIIO.LMID = 0; |
| @@ -1618,7 +1778,7 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
| 1618 | 1778 | ||
| 1619 | descriptor.HighPriority.RequestFlags = | 1779 | descriptor.HighPriority.RequestFlags = |
| 1620 | MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; | 1780 | MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; |
| 1621 | descriptor.HighPriority.MSIxIndex = 0; /* TODO */ | 1781 | descriptor.HighPriority.MSIxIndex = 0; |
| 1622 | descriptor.HighPriority.SMID = cpu_to_le16(smid); | 1782 | descriptor.HighPriority.SMID = cpu_to_le16(smid); |
| 1623 | descriptor.HighPriority.LMID = 0; | 1783 | descriptor.HighPriority.LMID = 0; |
| 1624 | descriptor.HighPriority.Reserved1 = 0; | 1784 | descriptor.HighPriority.Reserved1 = 0; |
| @@ -1640,7 +1800,7 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
| 1640 | u64 *request = (u64 *)&descriptor; | 1800 | u64 *request = (u64 *)&descriptor; |
| 1641 | 1801 | ||
| 1642 | descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; | 1802 | descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; |
| 1643 | descriptor.Default.MSIxIndex = 0; /* TODO */ | 1803 | descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); |
| 1644 | descriptor.Default.SMID = cpu_to_le16(smid); | 1804 | descriptor.Default.SMID = cpu_to_le16(smid); |
| 1645 | descriptor.Default.LMID = 0; | 1805 | descriptor.Default.LMID = 0; |
| 1646 | descriptor.Default.DescriptorTypeDependent = 0; | 1806 | descriptor.Default.DescriptorTypeDependent = 0; |
| @@ -1665,7 +1825,7 @@ mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, | |||
| 1665 | 1825 | ||
| 1666 | descriptor.SCSITarget.RequestFlags = | 1826 | descriptor.SCSITarget.RequestFlags = |
| 1667 | MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; | 1827 | MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; |
| 1668 | descriptor.SCSITarget.MSIxIndex = 0; /* TODO */ | 1828 | descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc); |
| 1669 | descriptor.SCSITarget.SMID = cpu_to_le16(smid); | 1829 | descriptor.SCSITarget.SMID = cpu_to_le16(smid); |
| 1670 | descriptor.SCSITarget.LMID = 0; | 1830 | descriptor.SCSITarget.LMID = 0; |
| 1671 | descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); | 1831 | descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); |
| @@ -2172,7 +2332,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 2172 | u16 max_sge_elements; | 2332 | u16 max_sge_elements; |
| 2173 | u16 num_of_reply_frames; | 2333 | u16 num_of_reply_frames; |
| 2174 | u16 chains_needed_per_io; | 2334 | u16 chains_needed_per_io; |
| 2175 | u32 sz, total_sz; | 2335 | u32 sz, total_sz, reply_post_free_sz; |
| 2176 | u32 retry_sz; | 2336 | u32 retry_sz; |
| 2177 | u16 max_request_credit; | 2337 | u16 max_request_credit; |
| 2178 | int i; | 2338 | int i; |
| @@ -2499,7 +2659,12 @@ chain_done: | |||
| 2499 | total_sz += sz; | 2659 | total_sz += sz; |
| 2500 | 2660 | ||
| 2501 | /* reply post queue, 16 byte align */ | 2661 | /* reply post queue, 16 byte align */ |
| 2502 | sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t); | 2662 | reply_post_free_sz = ioc->reply_post_queue_depth * |
| 2663 | sizeof(Mpi2DefaultReplyDescriptor_t); | ||
| 2664 | if (_base_is_controller_msix_enabled(ioc)) | ||
| 2665 | sz = reply_post_free_sz * ioc->reply_queue_count; | ||
| 2666 | else | ||
| 2667 | sz = reply_post_free_sz; | ||
| 2503 | ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", | 2668 | ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", |
| 2504 | ioc->pdev, sz, 16, 0); | 2669 | ioc->pdev, sz, 16, 0); |
| 2505 | if (!ioc->reply_post_free_dma_pool) { | 2670 | if (!ioc->reply_post_free_dma_pool) { |
| @@ -3187,6 +3352,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3187 | facts->MaxChainDepth = mpi_reply.MaxChainDepth; | 3352 | facts->MaxChainDepth = mpi_reply.MaxChainDepth; |
| 3188 | facts->WhoInit = mpi_reply.WhoInit; | 3353 | facts->WhoInit = mpi_reply.WhoInit; |
| 3189 | facts->NumberOfPorts = mpi_reply.NumberOfPorts; | 3354 | facts->NumberOfPorts = mpi_reply.NumberOfPorts; |
| 3355 | facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; | ||
| 3190 | facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); | 3356 | facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); |
| 3191 | facts->MaxReplyDescriptorPostQueueDepth = | 3357 | facts->MaxReplyDescriptorPostQueueDepth = |
| 3192 | le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); | 3358 | le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); |
| @@ -3244,7 +3410,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3244 | mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); | 3410 | mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); |
| 3245 | mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); | 3411 | mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); |
| 3246 | 3412 | ||
| 3247 | 3413 | if (_base_is_controller_msix_enabled(ioc)) | |
| 3414 | mpi_request.HostMSIxVectors = ioc->reply_queue_count; | ||
| 3248 | mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); | 3415 | mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); |
| 3249 | mpi_request.ReplyDescriptorPostQueueDepth = | 3416 | mpi_request.ReplyDescriptorPostQueueDepth = |
| 3250 | cpu_to_le16(ioc->reply_post_queue_depth); | 3417 | cpu_to_le16(ioc->reply_post_queue_depth); |
| @@ -3513,9 +3680,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3513 | u32 hcb_size; | 3680 | u32 hcb_size; |
| 3514 | 3681 | ||
| 3515 | printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); | 3682 | printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); |
| 3516 | |||
| 3517 | _base_save_msix_table(ioc); | ||
| 3518 | |||
| 3519 | drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", | 3683 | drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", |
| 3520 | ioc->name)); | 3684 | ioc->name)); |
| 3521 | 3685 | ||
| @@ -3611,7 +3775,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3611 | goto out; | 3775 | goto out; |
| 3612 | } | 3776 | } |
| 3613 | 3777 | ||
| 3614 | _base_restore_msix_table(ioc); | ||
| 3615 | printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); | 3778 | printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); |
| 3616 | return 0; | 3779 | return 0; |
| 3617 | 3780 | ||
| @@ -3692,6 +3855,9 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3692 | u16 smid; | 3855 | u16 smid; |
| 3693 | struct _tr_list *delayed_tr, *delayed_tr_next; | 3856 | struct _tr_list *delayed_tr, *delayed_tr_next; |
| 3694 | u8 hide_flag; | 3857 | u8 hide_flag; |
| 3858 | struct adapter_reply_queue *reply_q; | ||
| 3859 | long reply_post_free; | ||
| 3860 | u32 reply_post_free_sz; | ||
| 3695 | 3861 | ||
| 3696 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | 3862 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, |
| 3697 | __func__)); | 3863 | __func__)); |
| @@ -3757,19 +3923,43 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 3757 | ioc->reply_sz) | 3923 | ioc->reply_sz) |
| 3758 | ioc->reply_free[i] = cpu_to_le32(reply_address); | 3924 | ioc->reply_free[i] = cpu_to_le32(reply_address); |
| 3759 | 3925 | ||
| 3926 | /* initialize reply queues */ | ||
| 3927 | _base_assign_reply_queues(ioc); | ||
| 3928 | |||
| 3760 | /* initialize Reply Post Free Queue */ | 3929 | /* initialize Reply Post Free Queue */ |
| 3761 | for (i = 0; i < ioc->reply_post_queue_depth; i++) | 3930 | reply_post_free = (long)ioc->reply_post_free; |
| 3762 | ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX); | 3931 | reply_post_free_sz = ioc->reply_post_queue_depth * |
| 3932 | sizeof(Mpi2DefaultReplyDescriptor_t); | ||
| 3933 | list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { | ||
| 3934 | reply_q->reply_post_host_index = 0; | ||
| 3935 | reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) | ||
| 3936 | reply_post_free; | ||
| 3937 | for (i = 0; i < ioc->reply_post_queue_depth; i++) | ||
| 3938 | reply_q->reply_post_free[i].Words = | ||
| 3939 | cpu_to_le64(ULLONG_MAX); | ||
| 3940 | if (!_base_is_controller_msix_enabled(ioc)) | ||
| 3941 | goto skip_init_reply_post_free_queue; | ||
| 3942 | reply_post_free += reply_post_free_sz; | ||
| 3943 | } | ||
| 3944 | skip_init_reply_post_free_queue: | ||
| 3763 | 3945 | ||
| 3764 | r = _base_send_ioc_init(ioc, sleep_flag); | 3946 | r = _base_send_ioc_init(ioc, sleep_flag); |
| 3765 | if (r) | 3947 | if (r) |
| 3766 | return r; | 3948 | return r; |
| 3767 | 3949 | ||
| 3768 | /* initialize the index's */ | 3950 | /* initialize reply free host index */ |
| 3769 | ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; | 3951 | ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; |
| 3770 | ioc->reply_post_host_index = 0; | ||
| 3771 | writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); | 3952 | writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); |
| 3772 | writel(0, &ioc->chip->ReplyPostHostIndex); | 3953 | |
| 3954 | /* initialize reply post host index */ | ||
| 3955 | list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { | ||
| 3956 | writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, | ||
| 3957 | &ioc->chip->ReplyPostHostIndex); | ||
| 3958 | if (!_base_is_controller_msix_enabled(ioc)) | ||
| 3959 | goto skip_init_reply_post_host_index; | ||
| 3960 | } | ||
| 3961 | |||
| 3962 | skip_init_reply_post_host_index: | ||
| 3773 | 3963 | ||
| 3774 | _base_unmask_interrupts(ioc); | 3964 | _base_unmask_interrupts(ioc); |
| 3775 | r = _base_event_notification(ioc, sleep_flag); | 3965 | r = _base_event_notification(ioc, sleep_flag); |
| @@ -3820,14 +4010,10 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) | |||
| 3820 | ioc->shost_recovery = 1; | 4010 | ioc->shost_recovery = 1; |
| 3821 | _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); | 4011 | _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); |
| 3822 | ioc->shost_recovery = 0; | 4012 | ioc->shost_recovery = 0; |
| 3823 | if (ioc->pci_irq) { | 4013 | _base_free_irq(ioc); |
| 3824 | synchronize_irq(pdev->irq); | ||
| 3825 | free_irq(ioc->pci_irq, ioc); | ||
| 3826 | } | ||
| 3827 | _base_disable_msix(ioc); | 4014 | _base_disable_msix(ioc); |
| 3828 | if (ioc->chip_phys) | 4015 | if (ioc->chip_phys) |
| 3829 | iounmap(ioc->chip); | 4016 | iounmap(ioc->chip); |
| 3830 | ioc->pci_irq = -1; | ||
| 3831 | ioc->chip_phys = 0; | 4017 | ioc->chip_phys = 0; |
| 3832 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 4018 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
| 3833 | pci_disable_pcie_error_reporting(pdev); | 4019 | pci_disable_pcie_error_reporting(pdev); |
| @@ -3845,14 +4031,50 @@ int | |||
| 3845 | mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | 4031 | mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) |
| 3846 | { | 4032 | { |
| 3847 | int r, i; | 4033 | int r, i; |
| 4034 | int cpu_id, last_cpu_id = 0; | ||
| 3848 | 4035 | ||
| 3849 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | 4036 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, |
| 3850 | __func__)); | 4037 | __func__)); |
| 3851 | 4038 | ||
| 4039 | /* setup cpu_msix_table */ | ||
| 4040 | ioc->cpu_count = num_online_cpus(); | ||
| 4041 | for_each_online_cpu(cpu_id) | ||
| 4042 | last_cpu_id = cpu_id; | ||
| 4043 | ioc->cpu_msix_table_sz = last_cpu_id + 1; | ||
| 4044 | ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); | ||
| 4045 | ioc->reply_queue_count = 1; | ||
| 4046 | if (!ioc->cpu_msix_table) { | ||
| 4047 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " | ||
| 4048 | "cpu_msix_table failed!!!\n", ioc->name)); | ||
| 4049 | r = -ENOMEM; | ||
| 4050 | goto out_free_resources; | ||
| 4051 | } | ||
| 4052 | |||
| 4053 | if (ioc->is_warpdrive) { | ||
| 4054 | ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, | ||
| 4055 | sizeof(resource_size_t *), GFP_KERNEL); | ||
| 4056 | if (!ioc->reply_post_host_index) { | ||
| 4057 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation " | ||
| 4058 | "for cpu_msix_table failed!!!\n", ioc->name)); | ||
| 4059 | r = -ENOMEM; | ||
| 4060 | goto out_free_resources; | ||
| 4061 | } | ||
| 4062 | } | ||
| 4063 | |||
| 3852 | r = mpt2sas_base_map_resources(ioc); | 4064 | r = mpt2sas_base_map_resources(ioc); |
| 3853 | if (r) | 4065 | if (r) |
| 3854 | return r; | 4066 | return r; |
| 3855 | 4067 | ||
| 4068 | if (ioc->is_warpdrive) { | ||
| 4069 | ioc->reply_post_host_index[0] = | ||
| 4070 | (resource_size_t *)&ioc->chip->ReplyPostHostIndex; | ||
| 4071 | |||
| 4072 | for (i = 1; i < ioc->cpu_msix_table_sz; i++) | ||
| 4073 | ioc->reply_post_host_index[i] = (resource_size_t *) | ||
| 4074 | ((u8 *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) | ||
| 4075 | * 4))); | ||
| 4076 | } | ||
| 4077 | |||
| 3856 | pci_set_drvdata(ioc->pdev, ioc->shost); | 4078 | pci_set_drvdata(ioc->pdev, ioc->shost); |
| 3857 | r = _base_get_ioc_facts(ioc, CAN_SLEEP); | 4079 | r = _base_get_ioc_facts(ioc, CAN_SLEEP); |
| 3858 | if (r) | 4080 | if (r) |
| @@ -3973,6 +4195,9 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
| 3973 | mpt2sas_base_free_resources(ioc); | 4195 | mpt2sas_base_free_resources(ioc); |
| 3974 | _base_release_memory_pools(ioc); | 4196 | _base_release_memory_pools(ioc); |
| 3975 | pci_set_drvdata(ioc->pdev, NULL); | 4197 | pci_set_drvdata(ioc->pdev, NULL); |
| 4198 | kfree(ioc->cpu_msix_table); | ||
| 4199 | if (ioc->is_warpdrive) | ||
| 4200 | kfree(ioc->reply_post_host_index); | ||
| 3976 | kfree(ioc->pd_handles); | 4201 | kfree(ioc->pd_handles); |
| 3977 | kfree(ioc->tm_cmds.reply); | 4202 | kfree(ioc->tm_cmds.reply); |
| 3978 | kfree(ioc->transport_cmds.reply); | 4203 | kfree(ioc->transport_cmds.reply); |
| @@ -4010,6 +4235,9 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) | |||
| 4010 | mpt2sas_base_free_resources(ioc); | 4235 | mpt2sas_base_free_resources(ioc); |
| 4011 | _base_release_memory_pools(ioc); | 4236 | _base_release_memory_pools(ioc); |
| 4012 | pci_set_drvdata(ioc->pdev, NULL); | 4237 | pci_set_drvdata(ioc->pdev, NULL); |
| 4238 | kfree(ioc->cpu_msix_table); | ||
| 4239 | if (ioc->is_warpdrive) | ||
| 4240 | kfree(ioc->reply_post_host_index); | ||
| 4013 | kfree(ioc->pd_handles); | 4241 | kfree(ioc->pd_handles); |
| 4014 | kfree(ioc->pfacts); | 4242 | kfree(ioc->pfacts); |
| 4015 | kfree(ioc->ctl_cmds.reply); | 4243 | kfree(ioc->ctl_cmds.reply); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 8d5be2120c63..59354dba68c0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
| @@ -69,11 +69,11 @@ | |||
| 69 | #define MPT2SAS_DRIVER_NAME "mpt2sas" | 69 | #define MPT2SAS_DRIVER_NAME "mpt2sas" |
| 70 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" | 70 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" |
| 71 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" | 71 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" |
| 72 | #define MPT2SAS_DRIVER_VERSION "09.100.00.00" | 72 | #define MPT2SAS_DRIVER_VERSION "09.100.00.01" |
| 73 | #define MPT2SAS_MAJOR_VERSION 09 | 73 | #define MPT2SAS_MAJOR_VERSION 09 |
| 74 | #define MPT2SAS_MINOR_VERSION 100 | 74 | #define MPT2SAS_MINOR_VERSION 100 |
| 75 | #define MPT2SAS_BUILD_VERSION 00 | 75 | #define MPT2SAS_BUILD_VERSION 00 |
| 76 | #define MPT2SAS_RELEASE_VERSION 00 | 76 | #define MPT2SAS_RELEASE_VERSION 01 |
| 77 | 77 | ||
| 78 | /* | 78 | /* |
| 79 | * Set MPT2SAS_SG_DEPTH value based on user input. | 79 | * Set MPT2SAS_SG_DEPTH value based on user input. |
| @@ -544,6 +544,28 @@ struct _tr_list { | |||
| 544 | 544 | ||
| 545 | typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); | 545 | typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); |
| 546 | 546 | ||
| 547 | /** | ||
| 548 | * struct adapter_reply_queue - the reply queue struct | ||
| 549 | * @ioc: per adapter object | ||
| 550 | * @msix_index: msix index into vector table | ||
| 551 | * @vector: irq vector | ||
| 552 | * @reply_post_host_index: head index in the pool where FW completes IO | ||
| 553 | * @reply_post_free: reply post base virt address | ||
| 554 | * @name: the name registered to request_irq() | ||
| 555 | * @busy: isr is actively processing replies on another cpu | ||
| 556 | * @list: this list | ||
| 557 | */ | ||
| 558 | struct adapter_reply_queue { | ||
| 559 | struct MPT2SAS_ADAPTER *ioc; | ||
| 560 | u8 msix_index; | ||
| 561 | unsigned int vector; | ||
| 562 | u32 reply_post_host_index; | ||
| 563 | Mpi2ReplyDescriptorsUnion_t *reply_post_free; | ||
| 564 | char name[MPT_NAME_LENGTH]; | ||
| 565 | atomic_t busy; | ||
| 566 | struct list_head list; | ||
| 567 | }; | ||
| 568 | |||
| 547 | /* IOC Facts and Port Facts converted from little endian to cpu */ | 569 | /* IOC Facts and Port Facts converted from little endian to cpu */ |
| 548 | union mpi2_version_union { | 570 | union mpi2_version_union { |
| 549 | MPI2_VERSION_STRUCT Struct; | 571 | MPI2_VERSION_STRUCT Struct; |
| @@ -606,7 +628,7 @@ enum mutex_type { | |||
| 606 | * @list: ioc_list | 628 | * @list: ioc_list |
| 607 | * @shost: shost object | 629 | * @shost: shost object |
| 608 | * @id: unique adapter id | 630 | * @id: unique adapter id |
| 609 | * @pci_irq: irq number | 631 | * @cpu_count: number online cpus |
| 610 | * @name: generic ioc string | 632 | * @name: generic ioc string |
| 611 | * @tmp_string: tmp string used for logging | 633 | * @tmp_string: tmp string used for logging |
| 612 | * @pdev: pci pdev object | 634 | * @pdev: pci pdev object |
| @@ -636,8 +658,8 @@ enum mutex_type { | |||
| 636 | * @wait_for_port_enable_to_complete: | 658 | * @wait_for_port_enable_to_complete: |
| 637 | * @msix_enable: flag indicating msix is enabled | 659 | * @msix_enable: flag indicating msix is enabled |
| 638 | * @msix_vector_count: number msix vectors | 660 | * @msix_vector_count: number msix vectors |
| 639 | * @msix_table: virt address to the msix table | 661 | * @cpu_msix_table: table for mapping cpus to msix index |
| 640 | * @msix_table_backup: backup msix table | 662 | * @cpu_msix_table_sz: table size |
| 641 | * @scsi_io_cb_idx: shost generated commands | 663 | * @scsi_io_cb_idx: shost generated commands |
| 642 | * @tm_cb_idx: task management commands | 664 | * @tm_cb_idx: task management commands |
| 643 | * @scsih_cb_idx: scsih internal commands | 665 | * @scsih_cb_idx: scsih internal commands |
| @@ -728,7 +750,8 @@ enum mutex_type { | |||
| 728 | * @reply_post_queue_depth: reply post queue depth | 750 | * @reply_post_queue_depth: reply post queue depth |
| 729 | * @reply_post_free: pool for reply post (64bit descriptor) | 751 | * @reply_post_free: pool for reply post (64bit descriptor) |
| 730 | * @reply_post_free_dma: | 752 | * @reply_post_free_dma: |
| 731 | * @reply_post_free_dma_pool: | 753 | * @reply_queue_count: number of reply queue's |
| 754 | * @reply_queue_list: link list contaning the reply queue info | ||
| 732 | * @reply_post_host_index: head index in the pool where FW completes IO | 755 | * @reply_post_host_index: head index in the pool where FW completes IO |
| 733 | * @delayed_tr_list: target reset link list | 756 | * @delayed_tr_list: target reset link list |
| 734 | * @delayed_tr_volume_list: volume target reset link list | 757 | * @delayed_tr_volume_list: volume target reset link list |
| @@ -737,7 +760,7 @@ struct MPT2SAS_ADAPTER { | |||
| 737 | struct list_head list; | 760 | struct list_head list; |
| 738 | struct Scsi_Host *shost; | 761 | struct Scsi_Host *shost; |
| 739 | u8 id; | 762 | u8 id; |
| 740 | u32 pci_irq; | 763 | int cpu_count; |
| 741 | char name[MPT_NAME_LENGTH]; | 764 | char name[MPT_NAME_LENGTH]; |
| 742 | char tmp_string[MPT_STRING_LENGTH]; | 765 | char tmp_string[MPT_STRING_LENGTH]; |
| 743 | struct pci_dev *pdev; | 766 | struct pci_dev *pdev; |
| @@ -779,8 +802,9 @@ struct MPT2SAS_ADAPTER { | |||
| 779 | 802 | ||
| 780 | u8 msix_enable; | 803 | u8 msix_enable; |
| 781 | u16 msix_vector_count; | 804 | u16 msix_vector_count; |
| 782 | u32 *msix_table; | 805 | u8 *cpu_msix_table; |
| 783 | u32 *msix_table_backup; | 806 | resource_size_t **reply_post_host_index; |
| 807 | u16 cpu_msix_table_sz; | ||
| 784 | u32 ioc_reset_count; | 808 | u32 ioc_reset_count; |
| 785 | 809 | ||
| 786 | /* internal commands, callback index */ | 810 | /* internal commands, callback index */ |
| @@ -911,7 +935,8 @@ struct MPT2SAS_ADAPTER { | |||
| 911 | Mpi2ReplyDescriptorsUnion_t *reply_post_free; | 935 | Mpi2ReplyDescriptorsUnion_t *reply_post_free; |
| 912 | dma_addr_t reply_post_free_dma; | 936 | dma_addr_t reply_post_free_dma; |
| 913 | struct dma_pool *reply_post_free_dma_pool; | 937 | struct dma_pool *reply_post_free_dma_pool; |
| 914 | u32 reply_post_host_index; | 938 | u8 reply_queue_count; |
| 939 | struct list_head reply_queue_list; | ||
| 915 | 940 | ||
| 916 | struct list_head delayed_tr_list; | 941 | struct list_head delayed_tr_list; |
| 917 | struct list_head delayed_tr_volume_list; | 942 | struct list_head delayed_tr_volume_list; |
| @@ -955,6 +980,7 @@ void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid); | |||
| 955 | void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); | 980 | void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); |
| 956 | __le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, | 981 | __le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, |
| 957 | u16 smid); | 982 | u16 smid); |
| 983 | void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc); | ||
| 958 | 984 | ||
| 959 | /* hi-priority queue */ | 985 | /* hi-priority queue */ |
| 960 | u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); | 986 | u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 6861244249a3..2b1101076cfe 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | * USA. | 41 | * USA. |
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | #include <linux/version.h> | ||
| 45 | #include <linux/module.h> | 44 | #include <linux/module.h> |
| 46 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
| 47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 38ed0260959d..9adb0133d6fb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
| @@ -42,7 +42,6 @@ | |||
| 42 | * USA. | 42 | * USA. |
| 43 | */ | 43 | */ |
| 44 | 44 | ||
| 45 | #include <linux/version.h> | ||
| 46 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
| 47 | #include <linux/module.h> | 46 | #include <linux/module.h> |
| 48 | #include <linux/errno.h> | 47 | #include <linux/errno.h> |
| @@ -2705,6 +2704,33 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, | |||
| 2705 | static DEVICE_ATTR(ioc_reset_count, S_IRUGO, | 2704 | static DEVICE_ATTR(ioc_reset_count, S_IRUGO, |
| 2706 | _ctl_ioc_reset_count_show, NULL); | 2705 | _ctl_ioc_reset_count_show, NULL); |
| 2707 | 2706 | ||
| 2707 | /** | ||
| 2708 | * _ctl_ioc_reply_queue_count_show - number of reply queues | ||
| 2709 | * @cdev - pointer to embedded class device | ||
| 2710 | * @buf - the buffer returned | ||
| 2711 | * | ||
| 2712 | * This is number of reply queues | ||
| 2713 | * | ||
| 2714 | * A sysfs 'read-only' shost attribute. | ||
| 2715 | */ | ||
| 2716 | static ssize_t | ||
| 2717 | _ctl_ioc_reply_queue_count_show(struct device *cdev, | ||
| 2718 | struct device_attribute *attr, char *buf) | ||
| 2719 | { | ||
| 2720 | u8 reply_queue_count; | ||
| 2721 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
| 2722 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
| 2723 | |||
| 2724 | if ((ioc->facts.IOCCapabilities & | ||
| 2725 | MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) | ||
| 2726 | reply_queue_count = ioc->reply_queue_count; | ||
| 2727 | else | ||
| 2728 | reply_queue_count = 1; | ||
| 2729 | return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); | ||
| 2730 | } | ||
| 2731 | static DEVICE_ATTR(reply_queue_count, S_IRUGO, | ||
| 2732 | _ctl_ioc_reply_queue_count_show, NULL); | ||
| 2733 | |||
| 2708 | struct DIAG_BUFFER_START { | 2734 | struct DIAG_BUFFER_START { |
| 2709 | __le32 Size; | 2735 | __le32 Size; |
| 2710 | __le32 DiagVersion; | 2736 | __le32 DiagVersion; |
| @@ -2915,6 +2941,7 @@ struct device_attribute *mpt2sas_host_attrs[] = { | |||
| 2915 | &dev_attr_host_trace_buffer_size, | 2941 | &dev_attr_host_trace_buffer_size, |
| 2916 | &dev_attr_host_trace_buffer, | 2942 | &dev_attr_host_trace_buffer, |
| 2917 | &dev_attr_host_trace_buffer_enable, | 2943 | &dev_attr_host_trace_buffer_enable, |
| 2944 | &dev_attr_reply_queue_count, | ||
| 2918 | NULL, | 2945 | NULL, |
| 2919 | }; | 2946 | }; |
| 2920 | 2947 | ||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 6abd2fcc43e2..1da1aa1a11e2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | * USA. | 41 | * USA. |
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | #include <linux/version.h> | ||
| 45 | #include <linux/module.h> | 44 | #include <linux/module.h> |
| 46 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
| 47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
| @@ -2162,6 +2161,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) | |||
| 2162 | return 1; | 2161 | return 1; |
| 2163 | if (ioc->tm_cmds.smid != smid) | 2162 | if (ioc->tm_cmds.smid != smid) |
| 2164 | return 1; | 2163 | return 1; |
| 2164 | mpt2sas_base_flush_reply_queues(ioc); | ||
| 2165 | ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; | 2165 | ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; |
| 2166 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); | 2166 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); |
| 2167 | if (mpi_reply) { | 2167 | if (mpi_reply) { |
| @@ -7354,6 +7354,7 @@ _scsih_remove(struct pci_dev *pdev) | |||
| 7354 | } | 7354 | } |
| 7355 | 7355 | ||
| 7356 | sas_remove_host(shost); | 7356 | sas_remove_host(shost); |
| 7357 | mpt2sas_base_detach(ioc); | ||
| 7357 | list_del(&ioc->list); | 7358 | list_del(&ioc->list); |
| 7358 | scsi_remove_host(shost); | 7359 | scsi_remove_host(shost); |
| 7359 | scsi_host_put(shost); | 7360 | scsi_host_put(shost); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 15c798026217..230732241aa2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
| @@ -163,7 +163,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
| 163 | return -EIO; | 163 | return -EIO; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | memset(identify, 0, sizeof(identify)); | 166 | memset(identify, 0, sizeof(*identify)); |
| 167 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); | 167 | device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); |
| 168 | 168 | ||
| 169 | /* sas_address */ | 169 | /* sas_address */ |
