1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Linux MegaRAID driver for SAS based RAID controllers |
4 | * |
5 | * Copyright (c) 2009-2013 LSI Corporation |
6 | * Copyright (c) 2013-2016 Avago Technologies |
7 | * Copyright (c) 2016-2018 Broadcom Inc. |
8 | * |
9 | * FILE: megaraid_sas_fp.c |
10 | * |
11 | * Authors: Broadcom Inc. |
12 | * Sumant Patro |
13 | * Varad Talamacki |
14 | * Manoj Jose |
15 | * Kashyap Desai <kashyap.desai@broadcom.com> |
16 | * Sumit Saxena <sumit.saxena@broadcom.com> |
17 | * |
18 | * Send feedback to: megaraidlinux.pdl@broadcom.com |
19 | */ |
20 | |
21 | #include <linux/kernel.h> |
22 | #include <linux/types.h> |
23 | #include <linux/pci.h> |
24 | #include <linux/list.h> |
25 | #include <linux/moduleparam.h> |
26 | #include <linux/module.h> |
27 | #include <linux/spinlock.h> |
28 | #include <linux/interrupt.h> |
29 | #include <linux/delay.h> |
30 | #include <linux/uio.h> |
31 | #include <linux/uaccess.h> |
32 | #include <linux/fs.h> |
33 | #include <linux/compat.h> |
34 | #include <linux/blkdev.h> |
35 | #include <linux/poll.h> |
36 | #include <linux/irq_poll.h> |
37 | |
38 | #include <scsi/scsi.h> |
39 | #include <scsi/scsi_cmnd.h> |
40 | #include <scsi/scsi_device.h> |
41 | #include <scsi/scsi_host.h> |
42 | |
43 | #include "megaraid_sas_fusion.h" |
44 | #include "megaraid_sas.h" |
45 | #include <asm/div64.h> |
46 | |
47 | #define LB_PENDING_CMDS_DEFAULT 4 |
48 | static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; |
49 | module_param(lb_pending_cmds, int, 0444); |
50 | MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding " |
51 | "threshold. Valid Values are 1-128. Default: 4" ); |
52 | |
53 | |
54 | #define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) |
55 | #define MR_LD_STATE_OPTIMAL 3 |
56 | |
57 | #define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize) |
58 | #define SPAN_ROW_DATA_SIZE(map_, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize) |
59 | #define SPAN_INVALID 0xff |
60 | |
61 | /* Prototypes */ |
62 | static void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, |
63 | PLD_SPAN_INFO ldSpanInfo); |
64 | static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, |
65 | u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, |
66 | struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map); |
67 | static u64 get_row_from_strip(struct megasas_instance *instance, u32 ld, |
68 | u64 strip, struct MR_DRV_RAID_MAP_ALL *map); |
69 | |
70 | u32 mega_mod64(u64 dividend, u32 divisor) |
71 | { |
72 | u64 d; |
73 | u32 remainder; |
74 | |
75 | if (!divisor) |
76 | printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n" ); |
77 | d = dividend; |
78 | remainder = do_div(d, divisor); |
79 | return remainder; |
80 | } |
81 | |
82 | /** |
83 | * mega_div64_32 - Do a 64-bit division |
84 | * @dividend: Dividend |
85 | * @divisor: Divisor |
86 | * |
87 | * @return quotient |
88 | **/ |
89 | static u64 mega_div64_32(uint64_t dividend, uint32_t divisor) |
90 | { |
91 | u64 d = dividend; |
92 | |
93 | if (!divisor) |
94 | printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n" ); |
95 | |
96 | do_div(d, divisor); |
97 | |
98 | return d; |
99 | } |
100 | |
101 | struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) |
102 | { |
103 | return &map->raidMap.ldSpanMap[ld].ldRaid; |
104 | } |
105 | |
106 | static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld, |
107 | struct MR_DRV_RAID_MAP_ALL |
108 | *map) |
109 | { |
110 | return &map->raidMap.ldSpanMap[ld].spanBlock[0]; |
111 | } |
112 | |
113 | static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_DRV_RAID_MAP_ALL *map) |
114 | { |
115 | return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; |
116 | } |
117 | |
118 | u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_DRV_RAID_MAP_ALL *map) |
119 | { |
120 | return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]); |
121 | } |
122 | |
123 | u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_DRV_RAID_MAP_ALL *map) |
124 | { |
125 | return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef); |
126 | } |
127 | |
128 | __le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) |
129 | { |
130 | return map->raidMap.devHndlInfo[pd].curDevHdl; |
131 | } |
132 | |
133 | static u8 MR_PdInterfaceTypeGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) |
134 | { |
135 | return map->raidMap.devHndlInfo[pd].interfaceType; |
136 | } |
137 | |
138 | u16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) |
139 | { |
140 | return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId); |
141 | } |
142 | |
143 | u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map) |
144 | { |
145 | return map->raidMap.ldTgtIdToLd[ldTgtId]; |
146 | } |
147 | |
148 | static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, |
149 | struct MR_DRV_RAID_MAP_ALL *map) |
150 | { |
151 | return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; |
152 | } |
153 | |
154 | /* |
155 | * This function will Populate Driver Map using firmware raid map |
156 | */ |
157 | static int MR_PopulateDrvRaidMap(struct megasas_instance *instance, u64 map_id) |
158 | { |
159 | struct fusion_context *fusion = instance->ctrl_context; |
160 | struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; |
161 | struct MR_FW_RAID_MAP *pFwRaidMap = NULL; |
162 | int i, j; |
163 | u16 ld_count; |
164 | struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn; |
165 | struct MR_FW_RAID_MAP_EXT *fw_map_ext; |
166 | struct MR_RAID_MAP_DESC_TABLE *desc_table; |
167 | |
168 | |
169 | struct MR_DRV_RAID_MAP_ALL *drv_map = |
170 | fusion->ld_drv_map[(map_id & 1)]; |
171 | struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap; |
172 | void *raid_map_data = NULL; |
173 | |
174 | memset(drv_map, 0, fusion->drv_map_sz); |
175 | memset(pDrvRaidMap->ldTgtIdToLd, |
176 | 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN)); |
177 | |
178 | if (instance->max_raid_mapsize) { |
179 | fw_map_dyn = fusion->ld_map[(map_id & 1)]; |
180 | desc_table = |
181 | (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset)); |
182 | if (desc_table != fw_map_dyn->raid_map_desc_table) |
183 | dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n" , |
184 | desc_table, fw_map_dyn->raid_map_desc_table); |
185 | |
186 | ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count); |
187 | pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); |
188 | pDrvRaidMap->fpPdIoTimeoutSec = |
189 | fw_map_dyn->fp_pd_io_timeout_sec; |
190 | pDrvRaidMap->totalSize = |
191 | cpu_to_le32(sizeof(struct MR_DRV_RAID_MAP_ALL)); |
192 | /* point to actual data starting point*/ |
193 | raid_map_data = (void *)fw_map_dyn + |
194 | le32_to_cpu(fw_map_dyn->desc_table_offset) + |
195 | le32_to_cpu(fw_map_dyn->desc_table_size); |
196 | |
197 | for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) { |
198 | switch (le32_to_cpu(desc_table->raid_map_desc_type)) { |
199 | case RAID_MAP_DESC_TYPE_DEVHDL_INFO: |
200 | fw_map_dyn->dev_hndl_info = |
201 | (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); |
202 | memcpy(pDrvRaidMap->devHndlInfo, |
203 | fw_map_dyn->dev_hndl_info, |
204 | sizeof(struct MR_DEV_HANDLE_INFO) * |
205 | le32_to_cpu(desc_table->raid_map_desc_elements)); |
206 | break; |
207 | case RAID_MAP_DESC_TYPE_TGTID_INFO: |
208 | fw_map_dyn->ld_tgt_id_to_ld = |
209 | (u16 *)(raid_map_data + |
210 | le32_to_cpu(desc_table->raid_map_desc_offset)); |
211 | for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) { |
212 | pDrvRaidMap->ldTgtIdToLd[j] = |
213 | le16_to_cpu(fw_map_dyn->ld_tgt_id_to_ld[j]); |
214 | } |
215 | break; |
216 | case RAID_MAP_DESC_TYPE_ARRAY_INFO: |
217 | fw_map_dyn->ar_map_info = |
218 | (struct MR_ARRAY_INFO *) |
219 | (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); |
220 | memcpy(pDrvRaidMap->arMapInfo, |
221 | fw_map_dyn->ar_map_info, |
222 | sizeof(struct MR_ARRAY_INFO) * |
223 | le32_to_cpu(desc_table->raid_map_desc_elements)); |
224 | break; |
225 | case RAID_MAP_DESC_TYPE_SPAN_INFO: |
226 | fw_map_dyn->ld_span_map = |
227 | (struct MR_LD_SPAN_MAP *) |
228 | (raid_map_data + |
229 | le32_to_cpu(desc_table->raid_map_desc_offset)); |
230 | memcpy(pDrvRaidMap->ldSpanMap, |
231 | fw_map_dyn->ld_span_map, |
232 | sizeof(struct MR_LD_SPAN_MAP) * |
233 | le32_to_cpu(desc_table->raid_map_desc_elements)); |
234 | break; |
235 | default: |
236 | dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n" , |
237 | fw_map_dyn->desc_table_num_elements); |
238 | } |
239 | ++desc_table; |
240 | } |
241 | |
242 | } else if (instance->supportmax256vd) { |
243 | fw_map_ext = |
244 | (struct MR_FW_RAID_MAP_EXT *)fusion->ld_map[(map_id & 1)]; |
245 | ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); |
246 | if (ld_count > MAX_LOGICAL_DRIVES_EXT) { |
247 | dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n" ); |
248 | return 1; |
249 | } |
250 | |
251 | pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); |
252 | pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec; |
253 | for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++) |
254 | pDrvRaidMap->ldTgtIdToLd[i] = |
255 | (u16)fw_map_ext->ldTgtIdToLd[i]; |
256 | memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap, |
257 | sizeof(struct MR_LD_SPAN_MAP) * ld_count); |
258 | memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo, |
259 | sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT); |
260 | memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo, |
261 | sizeof(struct MR_DEV_HANDLE_INFO) * |
262 | MAX_RAIDMAP_PHYSICAL_DEVICES); |
263 | |
264 | /* New Raid map will not set totalSize, so keep expected value |
265 | * for legacy code in ValidateMapInfo |
266 | */ |
267 | pDrvRaidMap->totalSize = |
268 | cpu_to_le32(sizeof(struct MR_FW_RAID_MAP_EXT)); |
269 | } else { |
270 | fw_map_old = (struct MR_FW_RAID_MAP_ALL *) |
271 | fusion->ld_map[(map_id & 1)]; |
272 | pFwRaidMap = &fw_map_old->raidMap; |
273 | ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); |
274 | if (ld_count > MAX_LOGICAL_DRIVES) { |
275 | dev_dbg(&instance->pdev->dev, |
276 | "LD count exposed in RAID map in not valid\n" ); |
277 | return 1; |
278 | } |
279 | |
280 | pDrvRaidMap->totalSize = pFwRaidMap->totalSize; |
281 | pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); |
282 | pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; |
283 | for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) |
284 | pDrvRaidMap->ldTgtIdToLd[i] = |
285 | (u8)pFwRaidMap->ldTgtIdToLd[i]; |
286 | for (i = 0; i < ld_count; i++) { |
287 | pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; |
288 | } |
289 | memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo, |
290 | sizeof(struct MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS); |
291 | memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo, |
292 | sizeof(struct MR_DEV_HANDLE_INFO) * |
293 | MAX_RAIDMAP_PHYSICAL_DEVICES); |
294 | } |
295 | |
296 | return 0; |
297 | } |
298 | |
299 | /* |
300 | * This function will validate Map info data provided by FW |
301 | */ |
302 | u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id) |
303 | { |
304 | struct fusion_context *fusion; |
305 | struct MR_DRV_RAID_MAP_ALL *drv_map; |
306 | struct MR_DRV_RAID_MAP *pDrvRaidMap; |
307 | struct LD_LOAD_BALANCE_INFO *lbInfo; |
308 | PLD_SPAN_INFO ldSpanInfo; |
309 | struct MR_LD_RAID *raid; |
310 | u16 num_lds, i; |
311 | u16 ld; |
312 | u32 expected_size; |
313 | |
314 | if (MR_PopulateDrvRaidMap(instance, map_id)) |
315 | return 0; |
316 | |
317 | fusion = instance->ctrl_context; |
318 | drv_map = fusion->ld_drv_map[(map_id & 1)]; |
319 | pDrvRaidMap = &drv_map->raidMap; |
320 | |
321 | lbInfo = fusion->load_balance_info; |
322 | ldSpanInfo = fusion->log_to_span; |
323 | |
324 | if (instance->max_raid_mapsize) |
325 | expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL); |
326 | else if (instance->supportmax256vd) |
327 | expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); |
328 | else |
329 | expected_size = struct_size_t(struct MR_FW_RAID_MAP, |
330 | ldSpanMap, |
331 | le16_to_cpu(pDrvRaidMap->ldCount)); |
332 | |
333 | if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { |
334 | dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x" , |
335 | le32_to_cpu(pDrvRaidMap->totalSize)); |
336 | dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n" , |
337 | (unsigned int)expected_size); |
338 | dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n" , |
339 | (unsigned int)sizeof(struct MR_LD_SPAN_MAP), |
340 | le32_to_cpu(pDrvRaidMap->totalSize)); |
341 | return 0; |
342 | } |
343 | |
344 | if (instance->UnevenSpanSupport) |
345 | mr_update_span_set(map: drv_map, ldSpanInfo); |
346 | |
347 | if (lbInfo) |
348 | mr_update_load_balance_params(map: drv_map, lbInfo); |
349 | |
350 | num_lds = le16_to_cpu(drv_map->raidMap.ldCount); |
351 | |
352 | memcpy(instance->ld_ids_prev, |
353 | instance->ld_ids_from_raidmap, |
354 | sizeof(instance->ld_ids_from_raidmap)); |
355 | memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS); |
356 | /*Convert Raid capability values to CPU arch */ |
357 | for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) { |
358 | ld = MR_TargetIdToLdGet(ldTgtId: i, map: drv_map); |
359 | |
360 | /* For non existing VDs, iterate to next VD*/ |
361 | if (ld >= MEGASAS_MAX_SUPPORTED_LD_IDS) |
362 | continue; |
363 | |
364 | raid = MR_LdRaidGet(ld, map: drv_map); |
365 | le32_to_cpus((u32 *)&raid->capability); |
366 | instance->ld_ids_from_raidmap[i] = i; |
367 | num_lds--; |
368 | } |
369 | |
370 | return 1; |
371 | } |
372 | |
373 | static u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, |
374 | struct MR_DRV_RAID_MAP_ALL *map) |
375 | { |
376 | struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); |
377 | struct MR_QUAD_ELEMENT *quad; |
378 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
379 | u32 span, j; |
380 | |
381 | for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) { |
382 | |
383 | for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) { |
384 | quad = &pSpanBlock->block_span_info.quad[j]; |
385 | |
386 | if (le32_to_cpu(quad->diff) == 0) |
387 | return SPAN_INVALID; |
388 | if (le64_to_cpu(quad->logStart) <= row && row <= |
389 | le64_to_cpu(quad->logEnd) && (mega_mod64(dividend: row - le64_to_cpu(quad->logStart), |
390 | le32_to_cpu(quad->diff))) == 0) { |
391 | if (span_blk != NULL) { |
392 | u64 blk; |
393 | blk = mega_div64_32(dividend: (row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff)); |
394 | |
395 | blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift; |
396 | *span_blk = blk; |
397 | } |
398 | return span; |
399 | } |
400 | } |
401 | } |
402 | return SPAN_INVALID; |
403 | } |
404 | |
405 | /* |
406 | ****************************************************************************** |
407 | * |
408 | * This routine calculates the Span block for given row using spanset. |
409 | * |
410 | * Inputs : |
411 | * instance - HBA instance |
412 | * ld - Logical drive number |
413 | * row - Row number |
414 | * map - LD map |
415 | * |
416 | * Outputs : |
417 | * |
418 | * span - Span number |
419 | * block - Absolute Block number in the physical disk |
420 | * div_error - Devide error code. |
421 | */ |
422 | |
423 | static u32 mr_spanset_get_span_block(struct megasas_instance *instance, |
424 | u32 ld, u64 row, u64 *span_blk, struct MR_DRV_RAID_MAP_ALL *map) |
425 | { |
426 | struct fusion_context *fusion = instance->ctrl_context; |
427 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
428 | LD_SPAN_SET *span_set; |
429 | struct MR_QUAD_ELEMENT *quad; |
430 | u32 span, info; |
431 | PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; |
432 | |
433 | for (info = 0; info < MAX_QUAD_DEPTH; info++) { |
434 | span_set = &(ldSpanInfo[ld].span_set[info]); |
435 | |
436 | if (span_set->span_row_data_width == 0) |
437 | break; |
438 | |
439 | if (row > span_set->data_row_end) |
440 | continue; |
441 | |
442 | for (span = 0; span < raid->spanDepth; span++) |
443 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. |
444 | block_span_info.noElements) >= info+1) { |
445 | quad = &map->raidMap.ldSpanMap[ld]. |
446 | spanBlock[span]. |
447 | block_span_info.quad[info]; |
448 | if (le32_to_cpu(quad->diff) == 0) |
449 | return SPAN_INVALID; |
450 | if (le64_to_cpu(quad->logStart) <= row && |
451 | row <= le64_to_cpu(quad->logEnd) && |
452 | (mega_mod64(dividend: row - le64_to_cpu(quad->logStart), |
453 | le32_to_cpu(quad->diff))) == 0) { |
454 | if (span_blk != NULL) { |
455 | u64 blk; |
456 | blk = mega_div64_32 |
457 | (dividend: (row - le64_to_cpu(quad->logStart)), |
458 | le32_to_cpu(quad->diff)); |
459 | blk = (blk + le64_to_cpu(quad->offsetInSpan)) |
460 | << raid->stripeShift; |
461 | *span_blk = blk; |
462 | } |
463 | return span; |
464 | } |
465 | } |
466 | } |
467 | return SPAN_INVALID; |
468 | } |
469 | |
470 | /* |
471 | ****************************************************************************** |
472 | * |
473 | * This routine calculates the row for given strip using spanset. |
474 | * |
475 | * Inputs : |
476 | * instance - HBA instance |
477 | * ld - Logical drive number |
478 | * Strip - Strip |
479 | * map - LD map |
480 | * |
481 | * Outputs : |
482 | * |
483 | * row - row associated with strip |
484 | */ |
485 | |
486 | static u64 get_row_from_strip(struct megasas_instance *instance, |
487 | u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) |
488 | { |
489 | struct fusion_context *fusion = instance->ctrl_context; |
490 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
491 | LD_SPAN_SET *span_set; |
492 | PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; |
493 | u32 info, strip_offset, span, span_offset; |
494 | u64 span_set_Strip, span_set_Row, retval; |
495 | |
496 | for (info = 0; info < MAX_QUAD_DEPTH; info++) { |
497 | span_set = &(ldSpanInfo[ld].span_set[info]); |
498 | |
499 | if (span_set->span_row_data_width == 0) |
500 | break; |
501 | if (strip > span_set->data_strip_end) |
502 | continue; |
503 | |
504 | span_set_Strip = strip - span_set->data_strip_start; |
505 | strip_offset = mega_mod64(dividend: span_set_Strip, |
506 | divisor: span_set->span_row_data_width); |
507 | span_set_Row = mega_div64_32(dividend: span_set_Strip, |
508 | divisor: span_set->span_row_data_width) * span_set->diff; |
509 | for (span = 0, span_offset = 0; span < raid->spanDepth; span++) |
510 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. |
511 | block_span_info.noElements) >= info+1) { |
512 | if (strip_offset >= |
513 | span_set->strip_offset[span]) |
514 | span_offset++; |
515 | else |
516 | break; |
517 | } |
518 | |
519 | retval = (span_set->data_row_start + span_set_Row + |
520 | (span_offset - 1)); |
521 | return retval; |
522 | } |
523 | return -1LLU; |
524 | } |
525 | |
526 | |
527 | /* |
528 | ****************************************************************************** |
529 | * |
530 | * This routine calculates the Start Strip for given row using spanset. |
531 | * |
532 | * Inputs : |
533 | * instance - HBA instance |
534 | * ld - Logical drive number |
535 | * row - Row number |
536 | * map - LD map |
537 | * |
538 | * Outputs : |
539 | * |
540 | * Strip - Start strip associated with row |
541 | */ |
542 | |
543 | static u64 get_strip_from_row(struct megasas_instance *instance, |
544 | u32 ld, u64 row, struct MR_DRV_RAID_MAP_ALL *map) |
545 | { |
546 | struct fusion_context *fusion = instance->ctrl_context; |
547 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
548 | LD_SPAN_SET *span_set; |
549 | struct MR_QUAD_ELEMENT *quad; |
550 | PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; |
551 | u32 span, info; |
552 | u64 strip; |
553 | |
554 | for (info = 0; info < MAX_QUAD_DEPTH; info++) { |
555 | span_set = &(ldSpanInfo[ld].span_set[info]); |
556 | |
557 | if (span_set->span_row_data_width == 0) |
558 | break; |
559 | if (row > span_set->data_row_end) |
560 | continue; |
561 | |
562 | for (span = 0; span < raid->spanDepth; span++) |
563 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. |
564 | block_span_info.noElements) >= info+1) { |
565 | quad = &map->raidMap.ldSpanMap[ld]. |
566 | spanBlock[span].block_span_info.quad[info]; |
567 | if (le64_to_cpu(quad->logStart) <= row && |
568 | row <= le64_to_cpu(quad->logEnd) && |
569 | mega_mod64(dividend: (row - le64_to_cpu(quad->logStart)), |
570 | le32_to_cpu(quad->diff)) == 0) { |
571 | strip = mega_div64_32 |
572 | (dividend: ((row - span_set->data_row_start) |
573 | - le64_to_cpu(quad->logStart)), |
574 | le32_to_cpu(quad->diff)); |
575 | strip *= span_set->span_row_data_width; |
576 | strip += span_set->data_strip_start; |
577 | strip += span_set->strip_offset[span]; |
578 | return strip; |
579 | } |
580 | } |
581 | } |
582 | dev_err(&instance->pdev->dev, "get_strip_from_row" |
583 | "returns invalid strip for ld=%x, row=%lx\n" , |
584 | ld, (long unsigned int)row); |
585 | return -1; |
586 | } |
587 | |
588 | /* |
589 | ****************************************************************************** |
590 | * |
591 | * This routine calculates the Physical Arm for given strip using spanset. |
592 | * |
593 | * Inputs : |
594 | * instance - HBA instance |
595 | * ld - Logical drive number |
596 | * strip - Strip |
597 | * map - LD map |
598 | * |
599 | * Outputs : |
600 | * |
601 | * Phys Arm - Phys Arm associated with strip |
602 | */ |
603 | |
604 | static u32 get_arm_from_strip(struct megasas_instance *instance, |
605 | u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) |
606 | { |
607 | struct fusion_context *fusion = instance->ctrl_context; |
608 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
609 | LD_SPAN_SET *span_set; |
610 | PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; |
611 | u32 info, strip_offset, span, span_offset, retval; |
612 | |
613 | for (info = 0 ; info < MAX_QUAD_DEPTH; info++) { |
614 | span_set = &(ldSpanInfo[ld].span_set[info]); |
615 | |
616 | if (span_set->span_row_data_width == 0) |
617 | break; |
618 | if (strip > span_set->data_strip_end) |
619 | continue; |
620 | |
621 | strip_offset = (uint)mega_mod64 |
622 | (dividend: (strip - span_set->data_strip_start), |
623 | divisor: span_set->span_row_data_width); |
624 | |
625 | for (span = 0, span_offset = 0; span < raid->spanDepth; span++) |
626 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. |
627 | block_span_info.noElements) >= info+1) { |
628 | if (strip_offset >= |
629 | span_set->strip_offset[span]) |
630 | span_offset = |
631 | span_set->strip_offset[span]; |
632 | else |
633 | break; |
634 | } |
635 | |
636 | retval = (strip_offset - span_offset); |
637 | return retval; |
638 | } |
639 | |
640 | dev_err(&instance->pdev->dev, "get_arm_from_strip" |
641 | "returns invalid arm for ld=%x strip=%lx\n" , |
642 | ld, (long unsigned int)strip); |
643 | |
644 | return -1; |
645 | } |
646 | |
647 | /* This Function will return Phys arm */ |
648 | static u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe, |
649 | struct MR_DRV_RAID_MAP_ALL *map) |
650 | { |
651 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
652 | /* Need to check correct default value */ |
653 | u32 arm = 0; |
654 | |
655 | switch (raid->level) { |
656 | case 0: |
657 | case 5: |
658 | case 6: |
659 | arm = mega_mod64(dividend: stripe, SPAN_ROW_SIZE(map, ld, span)); |
660 | break; |
661 | case 1: |
662 | /* start with logical arm */ |
663 | arm = get_arm_from_strip(instance, ld, strip: stripe, map); |
664 | if (arm != -1U) |
665 | arm *= 2; |
666 | break; |
667 | } |
668 | |
669 | return arm; |
670 | } |
671 | |
672 | |
673 | /* |
674 | ****************************************************************************** |
675 | * |
676 | * This routine calculates the arm, span and block for the specified stripe and |
677 | * reference in stripe using spanset |
678 | * |
679 | * Inputs : |
680 | * |
681 | * ld - Logical drive number |
682 | * stripRow - Stripe number |
683 | * stripRef - Reference in stripe |
684 | * |
685 | * Outputs : |
686 | * |
687 | * span - Span number |
688 | * block - Absolute Block number in the physical disk |
689 | */ |
690 | static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, |
691 | u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, |
692 | struct RAID_CONTEXT *pRAID_Context, |
693 | struct MR_DRV_RAID_MAP_ALL *map) |
694 | { |
695 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
696 | u32 pd, arRef, r1_alt_pd; |
697 | u8 physArm, span; |
698 | u64 row; |
699 | u8 retval = true; |
700 | u64 *pdBlock = &io_info->pdBlock; |
701 | __le16 *pDevHandle = &io_info->devHandle; |
702 | u8 *pPdInterface = &io_info->pd_interface; |
703 | u32 logArm, rowMod, armQ, arm; |
704 | |
705 | *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); |
706 | |
707 | /*Get row and span from io_info for Uneven Span IO.*/ |
708 | row = io_info->start_row; |
709 | span = io_info->start_span; |
710 | |
711 | |
712 | if (raid->level == 6) { |
713 | logArm = get_arm_from_strip(instance, ld, strip: stripRow, map); |
714 | if (logArm == -1U) |
715 | return false; |
716 | rowMod = mega_mod64(dividend: row, SPAN_ROW_SIZE(map, ld, span)); |
717 | armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod; |
718 | arm = armQ + 1 + logArm; |
719 | if (arm >= SPAN_ROW_SIZE(map, ld, span)) |
720 | arm -= SPAN_ROW_SIZE(map, ld, span); |
721 | physArm = (u8)arm; |
722 | } else |
723 | /* Calculate the arm */ |
724 | physArm = get_arm(instance, ld, span, stripe: stripRow, map); |
725 | if (physArm == 0xFF) |
726 | return false; |
727 | |
728 | arRef = MR_LdSpanArrayGet(ld, span, map); |
729 | pd = MR_ArPdGet(ar: arRef, arm: physArm, map); |
730 | |
731 | if (pd != MR_PD_INVALID) { |
732 | *pDevHandle = MR_PdDevHandleGet(pd, map); |
733 | *pPdInterface = MR_PdInterfaceTypeGet(pd, map); |
734 | /* get second pd also for raid 1/10 fast path writes*/ |
735 | if ((instance->adapter_type >= VENTURA_SERIES) && |
736 | (raid->level == 1) && |
737 | !io_info->isRead) { |
738 | r1_alt_pd = MR_ArPdGet(ar: arRef, arm: physArm + 1, map); |
739 | if (r1_alt_pd != MR_PD_INVALID) |
740 | io_info->r1_alt_dev_handle = |
741 | MR_PdDevHandleGet(pd: r1_alt_pd, map); |
742 | } |
743 | } else { |
744 | if ((raid->level >= 5) && |
745 | ((instance->adapter_type == THUNDERBOLT_SERIES) || |
746 | ((instance->adapter_type == INVADER_SERIES) && |
747 | (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) |
748 | pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; |
749 | else if (raid->level == 1) { |
750 | physArm = physArm + 1; |
751 | pd = MR_ArPdGet(ar: arRef, arm: physArm, map); |
752 | if (pd != MR_PD_INVALID) { |
753 | *pDevHandle = MR_PdDevHandleGet(pd, map); |
754 | *pPdInterface = MR_PdInterfaceTypeGet(pd, map); |
755 | } |
756 | } |
757 | } |
758 | |
759 | *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); |
760 | if (instance->adapter_type >= VENTURA_SERIES) { |
761 | ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = |
762 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
763 | io_info->span_arm = |
764 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
765 | } else { |
766 | pRAID_Context->span_arm = |
767 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
768 | io_info->span_arm = pRAID_Context->span_arm; |
769 | } |
770 | io_info->pd_after_lb = pd; |
771 | return retval; |
772 | } |
773 | |
774 | /* |
775 | ****************************************************************************** |
776 | * |
777 | * This routine calculates the arm, span and block for the specified stripe and |
778 | * reference in stripe. |
779 | * |
780 | * Inputs : |
781 | * |
782 | * ld - Logical drive number |
783 | * stripRow - Stripe number |
784 | * stripRef - Reference in stripe |
785 | * |
786 | * Outputs : |
787 | * |
788 | * span - Span number |
789 | * block - Absolute Block number in the physical disk |
790 | */ |
791 | static u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, |
792 | u16 stripRef, struct IO_REQUEST_INFO *io_info, |
793 | struct RAID_CONTEXT *pRAID_Context, |
794 | struct MR_DRV_RAID_MAP_ALL *map) |
795 | { |
796 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
797 | u32 pd, arRef, r1_alt_pd; |
798 | u8 physArm, span; |
799 | u64 row; |
800 | u8 retval = true; |
801 | u64 *pdBlock = &io_info->pdBlock; |
802 | __le16 *pDevHandle = &io_info->devHandle; |
803 | u8 *pPdInterface = &io_info->pd_interface; |
804 | |
805 | *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); |
806 | |
807 | row = mega_div64_32(dividend: stripRow, divisor: raid->rowDataSize); |
808 | |
809 | if (raid->level == 6) { |
810 | /* logical arm within row */ |
811 | u32 logArm = mega_mod64(dividend: stripRow, divisor: raid->rowDataSize); |
812 | u32 rowMod, armQ, arm; |
813 | |
814 | if (raid->rowSize == 0) |
815 | return false; |
816 | /* get logical row mod */ |
817 | rowMod = mega_mod64(dividend: row, divisor: raid->rowSize); |
818 | armQ = raid->rowSize-1-rowMod; /* index of Q drive */ |
819 | arm = armQ+1+logArm; /* data always logically follows Q */ |
820 | if (arm >= raid->rowSize) /* handle wrap condition */ |
821 | arm -= raid->rowSize; |
822 | physArm = (u8)arm; |
823 | } else { |
824 | if (raid->modFactor == 0) |
825 | return false; |
826 | physArm = MR_LdDataArmGet(ld, armIdx: mega_mod64(dividend: stripRow, |
827 | divisor: raid->modFactor), |
828 | map); |
829 | } |
830 | |
831 | if (raid->spanDepth == 1) { |
832 | span = 0; |
833 | *pdBlock = row << raid->stripeShift; |
834 | } else { |
835 | span = (u8)MR_GetSpanBlock(ld, row, span_blk: pdBlock, map); |
836 | if (span == SPAN_INVALID) |
837 | return false; |
838 | } |
839 | |
840 | /* Get the array on which this span is present */ |
841 | arRef = MR_LdSpanArrayGet(ld, span, map); |
842 | pd = MR_ArPdGet(ar: arRef, arm: physArm, map); /* Get the pd */ |
843 | |
844 | if (pd != MR_PD_INVALID) { |
845 | /* Get dev handle from Pd. */ |
846 | *pDevHandle = MR_PdDevHandleGet(pd, map); |
847 | *pPdInterface = MR_PdInterfaceTypeGet(pd, map); |
848 | /* get second pd also for raid 1/10 fast path writes*/ |
849 | if ((instance->adapter_type >= VENTURA_SERIES) && |
850 | (raid->level == 1) && |
851 | !io_info->isRead) { |
852 | r1_alt_pd = MR_ArPdGet(ar: arRef, arm: physArm + 1, map); |
853 | if (r1_alt_pd != MR_PD_INVALID) |
854 | io_info->r1_alt_dev_handle = |
855 | MR_PdDevHandleGet(pd: r1_alt_pd, map); |
856 | } |
857 | } else { |
858 | if ((raid->level >= 5) && |
859 | ((instance->adapter_type == THUNDERBOLT_SERIES) || |
860 | ((instance->adapter_type == INVADER_SERIES) && |
861 | (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) |
862 | pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; |
863 | else if (raid->level == 1) { |
864 | /* Get alternate Pd. */ |
865 | physArm = physArm + 1; |
866 | pd = MR_ArPdGet(ar: arRef, arm: physArm, map); |
867 | if (pd != MR_PD_INVALID) { |
868 | /* Get dev handle from Pd */ |
869 | *pDevHandle = MR_PdDevHandleGet(pd, map); |
870 | *pPdInterface = MR_PdInterfaceTypeGet(pd, map); |
871 | } |
872 | } |
873 | } |
874 | |
875 | *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); |
876 | if (instance->adapter_type >= VENTURA_SERIES) { |
877 | ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = |
878 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
879 | io_info->span_arm = |
880 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
881 | } else { |
882 | pRAID_Context->span_arm = |
883 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; |
884 | io_info->span_arm = pRAID_Context->span_arm; |
885 | } |
886 | io_info->pd_after_lb = pd; |
887 | return retval; |
888 | } |
889 | |
890 | /* |
891 | * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation |
892 | * @instance: Adapter soft state |
893 | * @ld: LD index |
894 | * @stripNo: Strip Number |
895 | * @io_info: IO info structure pointer |
896 | * pRAID_Context: RAID context pointer |
897 | * map: RAID map pointer |
898 | * |
899 | * This routine calculates the logical arm, data Arm, row number and parity arm |
900 | * for R56 CTIO write operation. |
901 | */ |
902 | static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance, |
903 | u32 ld, u64 stripNo, |
904 | struct IO_REQUEST_INFO *io_info, |
905 | struct RAID_CONTEXT_G35 *pRAID_Context, |
906 | struct MR_DRV_RAID_MAP_ALL *map) |
907 | { |
908 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); |
909 | u8 span, dataArms, arms, dataArm, logArm; |
910 | s8 rightmostParityArm, PParityArm; |
911 | u64 rowNum; |
912 | u64 *pdBlock = &io_info->pdBlock; |
913 | |
914 | dataArms = raid->rowDataSize; |
915 | arms = raid->rowSize; |
916 | |
917 | rowNum = mega_div64_32(dividend: stripNo, divisor: dataArms); |
918 | /* parity disk arm, first arm is 0 */ |
919 | rightmostParityArm = (arms - 1) - mega_mod64(dividend: rowNum, divisor: arms); |
920 | |
921 | /* logical arm within row */ |
922 | logArm = mega_mod64(dividend: stripNo, divisor: dataArms); |
923 | /* physical arm for data */ |
924 | dataArm = mega_mod64(dividend: (rightmostParityArm + 1 + logArm), divisor: arms); |
925 | |
926 | if (raid->spanDepth == 1) { |
927 | span = 0; |
928 | } else { |
929 | span = (u8)MR_GetSpanBlock(ld, row: rowNum, span_blk: pdBlock, map); |
930 | if (span == SPAN_INVALID) |
931 | return; |
932 | } |
933 | |
934 | if (raid->level == 6) { |
935 | /* P Parity arm, note this can go negative adjust if negative */ |
936 | PParityArm = (arms - 2) - mega_mod64(dividend: rowNum, divisor: arms); |
937 | |
938 | if (PParityArm < 0) |
939 | PParityArm += arms; |
940 | |
941 | /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */ |
942 | pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm; |
943 | pRAID_Context->flow_specific.r56_arm_map |= |
944 | (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT); |
945 | } else { |
946 | pRAID_Context->flow_specific.r56_arm_map |= |
947 | (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT); |
948 | } |
949 | |
950 | pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum); |
951 | pRAID_Context->flow_specific.r56_arm_map |= |
952 | (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT); |
953 | cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map); |
954 | pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm; |
955 | pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD << |
956 | MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); |
957 | |
958 | return; |
959 | } |
960 | |
961 | /* |
962 | ****************************************************************************** |
963 | * |
964 | * MR_BuildRaidContext function |
965 | * |
966 | * This function will initiate command processing. The start/end row and strip |
967 | * information is calculated then the lock is acquired. |
968 | * This function will return 0 if region lock was acquired OR return num strips |
969 | */ |
970 | u8 |
971 | MR_BuildRaidContext(struct megasas_instance *instance, |
972 | struct IO_REQUEST_INFO *io_info, |
973 | struct RAID_CONTEXT *pRAID_Context, |
974 | struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN) |
975 | { |
976 | struct fusion_context *fusion; |
977 | struct MR_LD_RAID *raid; |
978 | u32 stripSize, stripe_mask; |
979 | u64 endLba, endStrip, endRow, start_row, start_strip; |
980 | u64 regStart; |
981 | u32 regSize; |
982 | u8 num_strips, numRows; |
983 | u16 ref_in_start_stripe, ref_in_end_stripe; |
984 | u64 ldStartBlock; |
985 | u32 numBlocks, ldTgtId; |
986 | u8 isRead; |
987 | u8 retval = 0; |
988 | u8 startlba_span = SPAN_INVALID; |
989 | u64 *pdBlock = &io_info->pdBlock; |
990 | u16 ld; |
991 | |
992 | ldStartBlock = io_info->ldStartBlock; |
993 | numBlocks = io_info->numBlocks; |
994 | ldTgtId = io_info->ldTgtId; |
995 | isRead = io_info->isRead; |
996 | io_info->IoforUnevenSpan = 0; |
997 | io_info->start_span = SPAN_INVALID; |
998 | fusion = instance->ctrl_context; |
999 | |
1000 | ld = MR_TargetIdToLdGet(ldTgtId, map); |
1001 | raid = MR_LdRaidGet(ld, map); |
1002 | /*check read ahead bit*/ |
1003 | io_info->ra_capable = raid->capability.ra_capable; |
1004 | |
1005 | /* |
1006 | * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero |
1007 | * return FALSE |
1008 | */ |
1009 | if (raid->rowDataSize == 0) { |
1010 | if (MR_LdSpanPtrGet(ld, span: 0, map)->spanRowDataSize == 0) |
1011 | return false; |
1012 | else if (instance->UnevenSpanSupport) { |
1013 | io_info->IoforUnevenSpan = 1; |
1014 | } else { |
1015 | dev_info(&instance->pdev->dev, |
1016 | "raid->rowDataSize is 0, but has SPAN[0]" |
1017 | "rowDataSize = 0x%0x," |
1018 | "but there is _NO_ UnevenSpanSupport\n" , |
1019 | MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); |
1020 | return false; |
1021 | } |
1022 | } |
1023 | |
1024 | stripSize = 1 << raid->stripeShift; |
1025 | stripe_mask = stripSize-1; |
1026 | |
1027 | io_info->data_arms = raid->rowDataSize; |
1028 | |
1029 | /* |
1030 | * calculate starting row and stripe, and number of strips and rows |
1031 | */ |
1032 | start_strip = ldStartBlock >> raid->stripeShift; |
1033 | ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask); |
1034 | endLba = ldStartBlock + numBlocks - 1; |
1035 | ref_in_end_stripe = (u16)(endLba & stripe_mask); |
1036 | endStrip = endLba >> raid->stripeShift; |
1037 | num_strips = (u8)(endStrip - start_strip + 1); /* End strip */ |
1038 | |
1039 | if (io_info->IoforUnevenSpan) { |
1040 | start_row = get_row_from_strip(instance, ld, strip: start_strip, map); |
1041 | endRow = get_row_from_strip(instance, ld, strip: endStrip, map); |
1042 | if (start_row == -1ULL || endRow == -1ULL) { |
1043 | dev_info(&instance->pdev->dev, "return from %s %d." |
1044 | "Send IO w/o region lock.\n" , |
1045 | __func__, __LINE__); |
1046 | return false; |
1047 | } |
1048 | |
1049 | if (raid->spanDepth == 1) { |
1050 | startlba_span = 0; |
1051 | *pdBlock = start_row << raid->stripeShift; |
1052 | } else |
1053 | startlba_span = (u8)mr_spanset_get_span_block(instance, |
1054 | ld, row: start_row, span_blk: pdBlock, map); |
1055 | if (startlba_span == SPAN_INVALID) { |
1056 | dev_info(&instance->pdev->dev, "return from %s %d" |
1057 | "for row 0x%llx,start strip %llx" |
1058 | "endSrip %llx\n" , __func__, __LINE__, |
1059 | (unsigned long long)start_row, |
1060 | (unsigned long long)start_strip, |
1061 | (unsigned long long)endStrip); |
1062 | return false; |
1063 | } |
1064 | io_info->start_span = startlba_span; |
1065 | io_info->start_row = start_row; |
1066 | } else { |
1067 | start_row = mega_div64_32(dividend: start_strip, divisor: raid->rowDataSize); |
1068 | endRow = mega_div64_32(dividend: endStrip, divisor: raid->rowDataSize); |
1069 | } |
1070 | numRows = (u8)(endRow - start_row + 1); |
1071 | |
1072 | /* |
1073 | * calculate region info. |
1074 | */ |
1075 | |
1076 | /* assume region is at the start of the first row */ |
1077 | regStart = start_row << raid->stripeShift; |
1078 | /* assume this IO needs the full row - we'll adjust if not true */ |
1079 | regSize = stripSize; |
1080 | |
1081 | io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock; |
1082 | |
1083 | /* Check if we can send this I/O via FastPath */ |
1084 | if (raid->capability.fpCapable) { |
1085 | if (isRead) |
1086 | io_info->fpOkForIo = (raid->capability.fpReadCapable && |
1087 | ((num_strips == 1) || |
1088 | raid->capability. |
1089 | fpReadAcrossStripe)); |
1090 | else |
1091 | io_info->fpOkForIo = (raid->capability.fpWriteCapable && |
1092 | ((num_strips == 1) || |
1093 | raid->capability. |
1094 | fpWriteAcrossStripe)); |
1095 | } else |
1096 | io_info->fpOkForIo = false; |
1097 | |
1098 | if (numRows == 1) { |
1099 | /* single-strip IOs can always lock only the data needed */ |
1100 | if (num_strips == 1) { |
1101 | regStart += ref_in_start_stripe; |
1102 | regSize = numBlocks; |
1103 | } |
1104 | /* multi-strip IOs always need to full stripe locked */ |
1105 | } else if (io_info->IoforUnevenSpan == 0) { |
1106 | /* |
1107 | * For Even span region lock optimization. |
1108 | * If the start strip is the last in the start row |
1109 | */ |
1110 | if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { |
1111 | regStart += ref_in_start_stripe; |
1112 | /* initialize count to sectors from startref to end |
1113 | of strip */ |
1114 | regSize = stripSize - ref_in_start_stripe; |
1115 | } |
1116 | |
1117 | /* add complete rows in the middle of the transfer */ |
1118 | if (numRows > 2) |
1119 | regSize += (numRows-2) << raid->stripeShift; |
1120 | |
1121 | /* if IO ends within first strip of last row*/ |
1122 | if (endStrip == endRow*raid->rowDataSize) |
1123 | regSize += ref_in_end_stripe+1; |
1124 | else |
1125 | regSize += stripSize; |
1126 | } else { |
1127 | /* |
1128 | * For Uneven span region lock optimization. |
1129 | * If the start strip is the last in the start row |
1130 | */ |
1131 | if (start_strip == (get_strip_from_row(instance, ld, row: start_row, map) + |
1132 | SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { |
1133 | regStart += ref_in_start_stripe; |
1134 | /* initialize count to sectors from |
1135 | * startRef to end of strip |
1136 | */ |
1137 | regSize = stripSize - ref_in_start_stripe; |
1138 | } |
1139 | /* Add complete rows in the middle of the transfer*/ |
1140 | |
1141 | if (numRows > 2) |
1142 | /* Add complete rows in the middle of the transfer*/ |
1143 | regSize += (numRows-2) << raid->stripeShift; |
1144 | |
1145 | /* if IO ends within first strip of last row */ |
1146 | if (endStrip == get_strip_from_row(instance, ld, row: endRow, map)) |
1147 | regSize += ref_in_end_stripe + 1; |
1148 | else |
1149 | regSize += stripSize; |
1150 | } |
1151 | |
1152 | pRAID_Context->timeout_value = |
1153 | cpu_to_le16(raid->fpIoTimeoutForLd ? |
1154 | raid->fpIoTimeoutForLd : |
1155 | map->raidMap.fpPdIoTimeoutSec); |
1156 | if (instance->adapter_type == INVADER_SERIES) |
1157 | pRAID_Context->reg_lock_flags = (isRead) ? |
1158 | raid->regTypeReqOnRead : raid->regTypeReqOnWrite; |
1159 | else if (instance->adapter_type == THUNDERBOLT_SERIES) |
1160 | pRAID_Context->reg_lock_flags = (isRead) ? |
1161 | REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; |
1162 | pRAID_Context->virtual_disk_tgt_id = raid->targetId; |
1163 | pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart); |
1164 | pRAID_Context->reg_lock_length = cpu_to_le32(regSize); |
1165 | pRAID_Context->config_seq_num = raid->seqNum; |
1166 | /* save pointer to raid->LUN array */ |
1167 | *raidLUN = raid->LUN; |
1168 | |
1169 | /* Aero R5/6 Division Offload for WRITE */ |
1170 | if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) { |
1171 | mr_get_phy_params_r56_rmw(instance, ld, stripNo: start_strip, io_info, |
1172 | pRAID_Context: (struct RAID_CONTEXT_G35 *)pRAID_Context, |
1173 | map); |
1174 | return true; |
1175 | } |
1176 | |
1177 | /*Get Phy Params only if FP capable, or else leave it to MR firmware |
1178 | to do the calculation.*/ |
1179 | if (io_info->fpOkForIo) { |
1180 | retval = io_info->IoforUnevenSpan ? |
1181 | mr_spanset_get_phy_params(instance, ld, |
1182 | stripRow: start_strip, stripRef: ref_in_start_stripe, |
1183 | io_info, pRAID_Context, map) : |
1184 | MR_GetPhyParams(instance, ld, stripRow: start_strip, |
1185 | stripRef: ref_in_start_stripe, io_info, |
1186 | pRAID_Context, map); |
1187 | /* If IO on an invalid Pd, then FP is not possible.*/ |
1188 | if (io_info->devHandle == MR_DEVHANDLE_INVALID) |
1189 | io_info->fpOkForIo = false; |
1190 | return retval; |
1191 | } else if (isRead) { |
1192 | uint stripIdx; |
1193 | for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { |
1194 | retval = io_info->IoforUnevenSpan ? |
1195 | mr_spanset_get_phy_params(instance, ld, |
1196 | stripRow: start_strip + stripIdx, |
1197 | stripRef: ref_in_start_stripe, io_info, |
1198 | pRAID_Context, map) : |
1199 | MR_GetPhyParams(instance, ld, |
1200 | stripRow: start_strip + stripIdx, stripRef: ref_in_start_stripe, |
1201 | io_info, pRAID_Context, map); |
1202 | if (!retval) |
1203 | return true; |
1204 | } |
1205 | } |
1206 | return true; |
1207 | } |
1208 | |
1209 | /* |
1210 | ****************************************************************************** |
1211 | * |
1212 | * This routine pepare spanset info from Valid Raid map and store it into |
1213 | * local copy of ldSpanInfo per instance data structure. |
1214 | * |
1215 | * Inputs : |
1216 | * map - LD map |
1217 | * ldSpanInfo - ldSpanInfo per HBA instance |
1218 | * |
1219 | */ |
1220 | void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, |
1221 | PLD_SPAN_INFO ldSpanInfo) |
1222 | { |
1223 | u8 span, count; |
1224 | u32 element, span_row_width; |
1225 | u64 span_row; |
1226 | struct MR_LD_RAID *raid; |
1227 | LD_SPAN_SET *span_set, *span_set_prev; |
1228 | struct MR_QUAD_ELEMENT *quad; |
1229 | int ldCount; |
1230 | u16 ld; |
1231 | |
1232 | |
1233 | for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { |
1234 | ld = MR_TargetIdToLdGet(ldTgtId: ldCount, map); |
1235 | if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) |
1236 | continue; |
1237 | raid = MR_LdRaidGet(ld, map); |
1238 | for (element = 0; element < MAX_QUAD_DEPTH; element++) { |
1239 | for (span = 0; span < raid->spanDepth; span++) { |
1240 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. |
1241 | block_span_info.noElements) < |
1242 | element + 1) |
1243 | continue; |
1244 | span_set = &(ldSpanInfo[ld].span_set[element]); |
1245 | quad = &map->raidMap.ldSpanMap[ld]. |
1246 | spanBlock[span].block_span_info. |
1247 | quad[element]; |
1248 | |
1249 | span_set->diff = le32_to_cpu(quad->diff); |
1250 | |
1251 | for (count = 0, span_row_width = 0; |
1252 | count < raid->spanDepth; count++) { |
1253 | if (le32_to_cpu(map->raidMap.ldSpanMap[ld]. |
1254 | spanBlock[count]. |
1255 | block_span_info. |
1256 | noElements) >= element + 1) { |
1257 | span_set->strip_offset[count] = |
1258 | span_row_width; |
1259 | span_row_width += |
1260 | MR_LdSpanPtrGet |
1261 | (ld, span: count, map)->spanRowDataSize; |
1262 | } |
1263 | } |
1264 | |
1265 | span_set->span_row_data_width = span_row_width; |
1266 | span_row = mega_div64_32(dividend: ((le64_to_cpu(quad->logEnd) - |
1267 | le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)), |
1268 | le32_to_cpu(quad->diff)); |
1269 | |
1270 | if (element == 0) { |
1271 | span_set->log_start_lba = 0; |
1272 | span_set->log_end_lba = |
1273 | ((span_row << raid->stripeShift) |
1274 | * span_row_width) - 1; |
1275 | |
1276 | span_set->span_row_start = 0; |
1277 | span_set->span_row_end = span_row - 1; |
1278 | |
1279 | span_set->data_strip_start = 0; |
1280 | span_set->data_strip_end = |
1281 | (span_row * span_row_width) - 1; |
1282 | |
1283 | span_set->data_row_start = 0; |
1284 | span_set->data_row_end = |
1285 | (span_row * le32_to_cpu(quad->diff)) - 1; |
1286 | } else { |
1287 | span_set_prev = &(ldSpanInfo[ld]. |
1288 | span_set[element - 1]); |
1289 | span_set->log_start_lba = |
1290 | span_set_prev->log_end_lba + 1; |
1291 | span_set->log_end_lba = |
1292 | span_set->log_start_lba + |
1293 | ((span_row << raid->stripeShift) |
1294 | * span_row_width) - 1; |
1295 | |
1296 | span_set->span_row_start = |
1297 | span_set_prev->span_row_end + 1; |
1298 | span_set->span_row_end = |
1299 | span_set->span_row_start + span_row - 1; |
1300 | |
1301 | span_set->data_strip_start = |
1302 | span_set_prev->data_strip_end + 1; |
1303 | span_set->data_strip_end = |
1304 | span_set->data_strip_start + |
1305 | (span_row * span_row_width) - 1; |
1306 | |
1307 | span_set->data_row_start = |
1308 | span_set_prev->data_row_end + 1; |
1309 | span_set->data_row_end = |
1310 | span_set->data_row_start + |
1311 | (span_row * le32_to_cpu(quad->diff)) - 1; |
1312 | } |
1313 | break; |
1314 | } |
1315 | if (span == raid->spanDepth) |
1316 | break; |
1317 | } |
1318 | } |
1319 | } |
1320 | |
1321 | void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map, |
1322 | struct LD_LOAD_BALANCE_INFO *lbInfo) |
1323 | { |
1324 | int ldCount; |
1325 | u16 ld; |
1326 | struct MR_LD_RAID *raid; |
1327 | |
1328 | if (lb_pending_cmds > 128 || lb_pending_cmds < 1) |
1329 | lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; |
1330 | |
1331 | for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { |
1332 | ld = MR_TargetIdToLdGet(ldTgtId: ldCount, map: drv_map); |
1333 | if (ld >= MAX_LOGICAL_DRIVES_EXT - 1) { |
1334 | lbInfo[ldCount].loadBalanceFlag = 0; |
1335 | continue; |
1336 | } |
1337 | |
1338 | raid = MR_LdRaidGet(ld, map: drv_map); |
1339 | if ((raid->level != 1) || |
1340 | (raid->ldState != MR_LD_STATE_OPTIMAL)) { |
1341 | lbInfo[ldCount].loadBalanceFlag = 0; |
1342 | continue; |
1343 | } |
1344 | lbInfo[ldCount].loadBalanceFlag = 1; |
1345 | } |
1346 | } |
1347 | |
1348 | static u8 megasas_get_best_arm_pd(struct megasas_instance *instance, |
1349 | struct LD_LOAD_BALANCE_INFO *lbInfo, |
1350 | struct IO_REQUEST_INFO *io_info, |
1351 | struct MR_DRV_RAID_MAP_ALL *drv_map) |
1352 | { |
1353 | struct MR_LD_RAID *raid; |
1354 | u16 pd1_dev_handle; |
1355 | u16 pend0, pend1, ld; |
1356 | u64 diff0, diff1; |
1357 | u8 bestArm, pd0, pd1, span, arm; |
1358 | u32 arRef, span_row_size; |
1359 | |
1360 | u64 block = io_info->ldStartBlock; |
1361 | u32 count = io_info->numBlocks; |
1362 | |
1363 | span = ((io_info->span_arm & RAID_CTX_SPANARM_SPAN_MASK) |
1364 | >> RAID_CTX_SPANARM_SPAN_SHIFT); |
1365 | arm = (io_info->span_arm & RAID_CTX_SPANARM_ARM_MASK); |
1366 | |
1367 | ld = MR_TargetIdToLdGet(ldTgtId: io_info->ldTgtId, map: drv_map); |
1368 | raid = MR_LdRaidGet(ld, map: drv_map); |
1369 | span_row_size = instance->UnevenSpanSupport ? |
1370 | SPAN_ROW_SIZE(drv_map, ld, span) : raid->rowSize; |
1371 | |
1372 | arRef = MR_LdSpanArrayGet(ld, span, map: drv_map); |
1373 | pd0 = MR_ArPdGet(ar: arRef, arm, map: drv_map); |
1374 | pd1 = MR_ArPdGet(ar: arRef, arm: (arm + 1) >= span_row_size ? |
1375 | (arm + 1 - span_row_size) : arm + 1, map: drv_map); |
1376 | |
1377 | /* Get PD1 Dev Handle */ |
1378 | |
1379 | pd1_dev_handle = MR_PdDevHandleGet(pd: pd1, map: drv_map); |
1380 | |
1381 | if (pd1_dev_handle == MR_DEVHANDLE_INVALID) { |
1382 | bestArm = arm; |
1383 | } else { |
1384 | /* get the pending cmds for the data and mirror arms */ |
1385 | pend0 = atomic_read(v: &lbInfo->scsi_pending_cmds[pd0]); |
1386 | pend1 = atomic_read(v: &lbInfo->scsi_pending_cmds[pd1]); |
1387 | |
1388 | /* Determine the disk whose head is nearer to the req. block */ |
1389 | diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); |
1390 | diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); |
1391 | bestArm = (diff0 <= diff1 ? arm : arm ^ 1); |
1392 | |
1393 | /* Make balance count from 16 to 4 to |
1394 | * keep driver in sync with Firmware |
1395 | */ |
1396 | if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || |
1397 | (bestArm != arm && pend1 > pend0 + lb_pending_cmds)) |
1398 | bestArm ^= 1; |
1399 | |
1400 | /* Update the last accessed block on the correct pd */ |
1401 | io_info->span_arm = |
1402 | (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; |
1403 | io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; |
1404 | } |
1405 | |
1406 | lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1; |
1407 | return io_info->pd_after_lb; |
1408 | } |
1409 | |
1410 | __le16 get_updated_dev_handle(struct megasas_instance *instance, |
1411 | struct LD_LOAD_BALANCE_INFO *lbInfo, |
1412 | struct IO_REQUEST_INFO *io_info, |
1413 | struct MR_DRV_RAID_MAP_ALL *drv_map) |
1414 | { |
1415 | u8 arm_pd; |
1416 | __le16 devHandle; |
1417 | |
1418 | /* get best new arm (PD ID) */ |
1419 | arm_pd = megasas_get_best_arm_pd(instance, lbInfo, io_info, drv_map); |
1420 | devHandle = MR_PdDevHandleGet(pd: arm_pd, map: drv_map); |
1421 | io_info->pd_interface = MR_PdInterfaceTypeGet(pd: arm_pd, map: drv_map); |
1422 | atomic_inc(v: &lbInfo->scsi_pending_cmds[arm_pd]); |
1423 | |
1424 | return devHandle; |
1425 | } |
1426 | |