megaraid_sas_fp.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. /*
  2. * Linux MegaRAID driver for SAS based RAID controllers
  3. *
  4. * Copyright (c) 2009-2012 LSI Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. * FILE: megaraid_sas_fp.c
  21. *
  22. * Authors: LSI Corporation
  23. * Sumant Patro
  24. * Varad Talamacki
  25. * Manoj Jose
  26. *
  27. * Send feedback to: <megaraidlinux@lsi.com>
  28. *
  29. * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
  30. * ATTN: Linuxraid
  31. */
  32. #include <linux/kernel.h>
  33. #include <linux/types.h>
  34. #include <linux/pci.h>
  35. #include <linux/list.h>
  36. #include <linux/moduleparam.h>
  37. #include <linux/module.h>
  38. #include <linux/spinlock.h>
  39. #include <linux/interrupt.h>
  40. #include <linux/delay.h>
  41. #include <linux/uio.h>
  42. #include <linux/uaccess.h>
  43. #include <linux/fs.h>
  44. #include <linux/compat.h>
  45. #include <linux/blkdev.h>
  46. #include <linux/poll.h>
  47. #include <scsi/scsi.h>
  48. #include <scsi/scsi_cmnd.h>
  49. #include <scsi/scsi_device.h>
  50. #include <scsi/scsi_host.h>
  51. #include "megaraid_sas_fusion.h"
  52. #include "megaraid_sas.h"
  53. #include <asm/div64.h>
  54. #define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
  55. #define MR_LD_STATE_OPTIMAL 3
  56. #define FALSE 0
  57. #define TRUE 1
  58. #define SPAN_DEBUG 0
  59. #define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize)
  60. #define SPAN_ROW_DATA_SIZE(map_, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize)
  61. #define SPAN_INVALID 0xff
  62. /* Prototypes */
  63. void mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
  64. struct LD_LOAD_BALANCE_INFO *lbInfo);
  65. static void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
  66. PLD_SPAN_INFO ldSpanInfo);
  67. static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
  68. u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,
  69. struct RAID_CONTEXT *pRAID_Context, struct MR_FW_RAID_MAP_ALL *map);
  70. static u64 get_row_from_strip(struct megasas_instance *instance, u32 ld,
  71. u64 strip, struct MR_FW_RAID_MAP_ALL *map);
  72. u32 mega_mod64(u64 dividend, u32 divisor)
  73. {
  74. u64 d;
  75. u32 remainder;
  76. if (!divisor)
  77. printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
  78. d = dividend;
  79. remainder = do_div(d, divisor);
  80. return remainder;
  81. }
  82. /**
  83. * @param dividend : Dividend
  84. * @param divisor : Divisor
  85. *
  86. * @return quotient
  87. **/
  88. u64 mega_div64_32(uint64_t dividend, uint32_t divisor)
  89. {
  90. u32 remainder;
  91. u64 d;
  92. if (!divisor)
  93. printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");
  94. d = dividend;
  95. remainder = do_div(d, divisor);
  96. return d;
  97. }
  98. struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
  99. {
  100. return &map->raidMap.ldSpanMap[ld].ldRaid;
  101. }
  102. static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,
  103. struct MR_FW_RAID_MAP_ALL
  104. *map)
  105. {
  106. return &map->raidMap.ldSpanMap[ld].spanBlock[0];
  107. }
  108. static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
  109. {
  110. return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
  111. }
  112. static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
  113. {
  114. return map->raidMap.arMapInfo[ar].pd[arm];
  115. }
  116. static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
  117. {
  118. return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
  119. }
  120. static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
  121. {
  122. return map->raidMap.devHndlInfo[pd].curDevHdl;
  123. }
  124. u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
  125. {
  126. return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
  127. }
  128. u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
  129. {
  130. return map->raidMap.ldTgtIdToLd[ldTgtId];
  131. }
  132. static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
  133. struct MR_FW_RAID_MAP_ALL *map)
  134. {
  135. return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
  136. }
  137. /*
  138. * This function will validate Map info data provided by FW
  139. */
  140. u8 MR_ValidateMapInfo(struct megasas_instance *instance)
  141. {
  142. struct fusion_context *fusion = instance->ctrl_context;
  143. struct MR_FW_RAID_MAP_ALL *map = fusion->ld_map[(instance->map_id & 1)];
  144. struct LD_LOAD_BALANCE_INFO *lbInfo = fusion->load_balance_info;
  145. PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
  146. struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
  147. if (pFwRaidMap->totalSize !=
  148. (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
  149. (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) {
  150. printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
  151. (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
  152. sizeof(struct MR_LD_SPAN_MAP)) +
  153. (sizeof(struct MR_LD_SPAN_MAP) *
  154. pFwRaidMap->ldCount)));
  155. printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
  156. ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
  157. pFwRaidMap->totalSize);
  158. return 0;
  159. }
  160. if (instance->UnevenSpanSupport)
  161. mr_update_span_set(map, ldSpanInfo);
  162. mr_update_load_balance_params(map, lbInfo);
  163. return 1;
  164. }
  165. u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
  166. struct MR_FW_RAID_MAP_ALL *map)
  167. {
  168. struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
  169. struct MR_QUAD_ELEMENT *quad;
  170. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  171. u32 span, j;
  172. for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
  173. for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
  174. quad = &pSpanBlock->block_span_info.quad[j];
  175. if (quad->diff == 0)
  176. return SPAN_INVALID;
  177. if (quad->logStart <= row && row <= quad->logEnd &&
  178. (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
  179. if (span_blk != NULL) {
  180. u64 blk, debugBlk;
  181. blk =
  182. mega_div64_32(
  183. (row-quad->logStart),
  184. quad->diff);
  185. debugBlk = blk;
  186. blk = (blk + quad->offsetInSpan) <<
  187. raid->stripeShift;
  188. *span_blk = blk;
  189. }
  190. return span;
  191. }
  192. }
  193. }
  194. return SPAN_INVALID;
  195. }
  196. /*
  197. ******************************************************************************
  198. *
  199. * Function to print info about span set created in driver from FW raid map
  200. *
  201. * Inputs :
  202. * map - LD map
  203. * ldSpanInfo - ldSpanInfo per HBA instance
  204. */
  205. #if SPAN_DEBUG
  206. static int getSpanInfo(struct MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
  207. {
  208. u8 span;
  209. u32 element;
  210. struct MR_LD_RAID *raid;
  211. LD_SPAN_SET *span_set;
  212. struct MR_QUAD_ELEMENT *quad;
  213. int ldCount;
  214. u16 ld;
  215. for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
  216. ld = MR_TargetIdToLdGet(ldCount, map);
  217. if (ld >= MAX_LOGICAL_DRIVES)
  218. continue;
  219. raid = MR_LdRaidGet(ld, map);
  220. dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n",
  221. ld, raid->spanDepth);
  222. for (span = 0; span < raid->spanDepth; span++)
  223. dev_dbg(&instance->pdev->dev, "Span=%x,"
  224. " number of quads=%x\n", span,
  225. map->raidMap.ldSpanMap[ld].spanBlock[span].
  226. block_span_info.noElements);
  227. for (element = 0; element < MAX_QUAD_DEPTH; element++) {
  228. span_set = &(ldSpanInfo[ld].span_set[element]);
  229. if (span_set->span_row_data_width == 0)
  230. break;
  231. dev_dbg(&instance->pdev->dev, "Span Set %x:"
  232. "width=%x, diff=%x\n", element,
  233. (unsigned int)span_set->span_row_data_width,
  234. (unsigned int)span_set->diff);
  235. dev_dbg(&instance->pdev->dev, "logical LBA"
  236. "start=0x%08lx, end=0x%08lx\n",
  237. (long unsigned int)span_set->log_start_lba,
  238. (long unsigned int)span_set->log_end_lba);
  239. dev_dbg(&instance->pdev->dev, "span row start=0x%08lx,"
  240. " end=0x%08lx\n",
  241. (long unsigned int)span_set->span_row_start,
  242. (long unsigned int)span_set->span_row_end);
  243. dev_dbg(&instance->pdev->dev, "data row start=0x%08lx,"
  244. " end=0x%08lx\n",
  245. (long unsigned int)span_set->data_row_start,
  246. (long unsigned int)span_set->data_row_end);
  247. dev_dbg(&instance->pdev->dev, "data strip start=0x%08lx,"
  248. " end=0x%08lx\n",
  249. (long unsigned int)span_set->data_strip_start,
  250. (long unsigned int)span_set->data_strip_end);
  251. for (span = 0; span < raid->spanDepth; span++) {
  252. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  253. block_span_info.noElements >=
  254. element + 1) {
  255. quad = &map->raidMap.ldSpanMap[ld].
  256. spanBlock[span].block_span_info.
  257. quad[element];
  258. dev_dbg(&instance->pdev->dev, "Span=%x,"
  259. "Quad=%x, diff=%x\n", span,
  260. element, quad->diff);
  261. dev_dbg(&instance->pdev->dev,
  262. "offset_in_span=0x%08lx\n",
  263. (long unsigned int)quad->offsetInSpan);
  264. dev_dbg(&instance->pdev->dev,
  265. "logical start=0x%08lx, end=0x%08lx\n",
  266. (long unsigned int)quad->logStart,
  267. (long unsigned int)quad->logEnd);
  268. }
  269. }
  270. }
  271. }
  272. return 0;
  273. }
  274. #endif
  275. /*
  276. ******************************************************************************
  277. *
  278. * This routine calculates the Span block for given row using spanset.
  279. *
  280. * Inputs :
  281. * instance - HBA instance
  282. * ld - Logical drive number
  283. * row - Row number
  284. * map - LD map
  285. *
  286. * Outputs :
  287. *
  288. * span - Span number
  289. * block - Absolute Block number in the physical disk
  290. * div_error - Devide error code.
  291. */
  292. u32 mr_spanset_get_span_block(struct megasas_instance *instance,
  293. u32 ld, u64 row, u64 *span_blk, struct MR_FW_RAID_MAP_ALL *map)
  294. {
  295. struct fusion_context *fusion = instance->ctrl_context;
  296. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  297. LD_SPAN_SET *span_set;
  298. struct MR_QUAD_ELEMENT *quad;
  299. u32 span, info;
  300. PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
  301. for (info = 0; info < MAX_QUAD_DEPTH; info++) {
  302. span_set = &(ldSpanInfo[ld].span_set[info]);
  303. if (span_set->span_row_data_width == 0)
  304. break;
  305. if (row > span_set->data_row_end)
  306. continue;
  307. for (span = 0; span < raid->spanDepth; span++)
  308. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  309. block_span_info.noElements >= info+1) {
  310. quad = &map->raidMap.ldSpanMap[ld].
  311. spanBlock[span].
  312. block_span_info.quad[info];
  313. if (quad->diff == 0)
  314. return SPAN_INVALID;
  315. if (quad->logStart <= row &&
  316. row <= quad->logEnd &&
  317. (mega_mod64(row - quad->logStart,
  318. quad->diff)) == 0) {
  319. if (span_blk != NULL) {
  320. u64 blk;
  321. blk = mega_div64_32
  322. ((row - quad->logStart),
  323. quad->diff);
  324. blk = (blk + quad->offsetInSpan)
  325. << raid->stripeShift;
  326. *span_blk = blk;
  327. }
  328. return span;
  329. }
  330. }
  331. }
  332. return SPAN_INVALID;
  333. }
  334. /*
  335. ******************************************************************************
  336. *
  337. * This routine calculates the row for given strip using spanset.
  338. *
  339. * Inputs :
  340. * instance - HBA instance
  341. * ld - Logical drive number
  342. * Strip - Strip
  343. * map - LD map
  344. *
  345. * Outputs :
  346. *
  347. * row - row associated with strip
  348. */
  349. static u64 get_row_from_strip(struct megasas_instance *instance,
  350. u32 ld, u64 strip, struct MR_FW_RAID_MAP_ALL *map)
  351. {
  352. struct fusion_context *fusion = instance->ctrl_context;
  353. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  354. LD_SPAN_SET *span_set;
  355. PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
  356. u32 info, strip_offset, span, span_offset;
  357. u64 span_set_Strip, span_set_Row, retval;
  358. for (info = 0; info < MAX_QUAD_DEPTH; info++) {
  359. span_set = &(ldSpanInfo[ld].span_set[info]);
  360. if (span_set->span_row_data_width == 0)
  361. break;
  362. if (strip > span_set->data_strip_end)
  363. continue;
  364. span_set_Strip = strip - span_set->data_strip_start;
  365. strip_offset = mega_mod64(span_set_Strip,
  366. span_set->span_row_data_width);
  367. span_set_Row = mega_div64_32(span_set_Strip,
  368. span_set->span_row_data_width) * span_set->diff;
  369. for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
  370. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  371. block_span_info.noElements >= info+1) {
  372. if (strip_offset >=
  373. span_set->strip_offset[span])
  374. span_offset++;
  375. else
  376. break;
  377. }
  378. #if SPAN_DEBUG
  379. dev_info(&instance->pdev->dev, "Strip 0x%llx,"
  380. "span_set_Strip 0x%llx, span_set_Row 0x%llx"
  381. "data width 0x%llx span offset 0x%x\n", strip,
  382. (unsigned long long)span_set_Strip,
  383. (unsigned long long)span_set_Row,
  384. (unsigned long long)span_set->span_row_data_width,
  385. span_offset);
  386. dev_info(&instance->pdev->dev, "For strip 0x%llx"
  387. "row is 0x%llx\n", strip,
  388. (unsigned long long) span_set->data_row_start +
  389. (unsigned long long) span_set_Row + (span_offset - 1));
  390. #endif
  391. retval = (span_set->data_row_start + span_set_Row +
  392. (span_offset - 1));
  393. return retval;
  394. }
  395. return -1LLU;
  396. }
  397. /*
  398. ******************************************************************************
  399. *
  400. * This routine calculates the Start Strip for given row using spanset.
  401. *
  402. * Inputs :
  403. * instance - HBA instance
  404. * ld - Logical drive number
  405. * row - Row number
  406. * map - LD map
  407. *
  408. * Outputs :
  409. *
  410. * Strip - Start strip associated with row
  411. */
  412. static u64 get_strip_from_row(struct megasas_instance *instance,
  413. u32 ld, u64 row, struct MR_FW_RAID_MAP_ALL *map)
  414. {
  415. struct fusion_context *fusion = instance->ctrl_context;
  416. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  417. LD_SPAN_SET *span_set;
  418. struct MR_QUAD_ELEMENT *quad;
  419. PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
  420. u32 span, info;
  421. u64 strip;
  422. for (info = 0; info < MAX_QUAD_DEPTH; info++) {
  423. span_set = &(ldSpanInfo[ld].span_set[info]);
  424. if (span_set->span_row_data_width == 0)
  425. break;
  426. if (row > span_set->data_row_end)
  427. continue;
  428. for (span = 0; span < raid->spanDepth; span++)
  429. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  430. block_span_info.noElements >= info+1) {
  431. quad = &map->raidMap.ldSpanMap[ld].
  432. spanBlock[span].block_span_info.quad[info];
  433. if (quad->logStart <= row &&
  434. row <= quad->logEnd &&
  435. mega_mod64((row - quad->logStart),
  436. quad->diff) == 0) {
  437. strip = mega_div64_32
  438. (((row - span_set->data_row_start)
  439. - quad->logStart),
  440. quad->diff);
  441. strip *= span_set->span_row_data_width;
  442. strip += span_set->data_strip_start;
  443. strip += span_set->strip_offset[span];
  444. return strip;
  445. }
  446. }
  447. }
  448. dev_err(&instance->pdev->dev, "get_strip_from_row"
  449. "returns invalid strip for ld=%x, row=%lx\n",
  450. ld, (long unsigned int)row);
  451. return -1;
  452. }
  453. /*
  454. ******************************************************************************
  455. *
  456. * This routine calculates the Physical Arm for given strip using spanset.
  457. *
  458. * Inputs :
  459. * instance - HBA instance
  460. * ld - Logical drive number
  461. * strip - Strip
  462. * map - LD map
  463. *
  464. * Outputs :
  465. *
  466. * Phys Arm - Phys Arm associated with strip
  467. */
  468. static u32 get_arm_from_strip(struct megasas_instance *instance,
  469. u32 ld, u64 strip, struct MR_FW_RAID_MAP_ALL *map)
  470. {
  471. struct fusion_context *fusion = instance->ctrl_context;
  472. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  473. LD_SPAN_SET *span_set;
  474. PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
  475. u32 info, strip_offset, span, span_offset, retval;
  476. for (info = 0 ; info < MAX_QUAD_DEPTH; info++) {
  477. span_set = &(ldSpanInfo[ld].span_set[info]);
  478. if (span_set->span_row_data_width == 0)
  479. break;
  480. if (strip > span_set->data_strip_end)
  481. continue;
  482. strip_offset = (uint)mega_mod64
  483. ((strip - span_set->data_strip_start),
  484. span_set->span_row_data_width);
  485. for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
  486. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  487. block_span_info.noElements >= info+1) {
  488. if (strip_offset >=
  489. span_set->strip_offset[span])
  490. span_offset =
  491. span_set->strip_offset[span];
  492. else
  493. break;
  494. }
  495. #if SPAN_DEBUG
  496. dev_info(&instance->pdev->dev, "get_arm_from_strip:"
  497. "for ld=0x%x strip=0x%lx arm is 0x%x\n", ld,
  498. (long unsigned int)strip, (strip_offset - span_offset));
  499. #endif
  500. retval = (strip_offset - span_offset);
  501. return retval;
  502. }
  503. dev_err(&instance->pdev->dev, "get_arm_from_strip"
  504. "returns invalid arm for ld=%x strip=%lx\n",
  505. ld, (long unsigned int)strip);
  506. return -1;
  507. }
  508. /* This Function will return Phys arm */
  509. u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe,
  510. struct MR_FW_RAID_MAP_ALL *map)
  511. {
  512. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  513. /* Need to check correct default value */
  514. u32 arm = 0;
  515. switch (raid->level) {
  516. case 0:
  517. case 5:
  518. case 6:
  519. arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
  520. break;
  521. case 1:
  522. /* start with logical arm */
  523. arm = get_arm_from_strip(instance, ld, stripe, map);
  524. if (arm != -1UL)
  525. arm *= 2;
  526. break;
  527. }
  528. return arm;
  529. }
  530. /*
  531. ******************************************************************************
  532. *
  533. * This routine calculates the arm, span and block for the specified stripe and
  534. * reference in stripe using spanset
  535. *
  536. * Inputs :
  537. *
  538. * ld - Logical drive number
  539. * stripRow - Stripe number
  540. * stripRef - Reference in stripe
  541. *
  542. * Outputs :
  543. *
  544. * span - Span number
  545. * block - Absolute Block number in the physical disk
  546. */
  547. static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
  548. u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,
  549. struct RAID_CONTEXT *pRAID_Context,
  550. struct MR_FW_RAID_MAP_ALL *map)
  551. {
  552. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  553. u32 pd, arRef;
  554. u8 physArm, span;
  555. u64 row;
  556. u8 retval = TRUE;
  557. u8 do_invader = 0;
  558. u64 *pdBlock = &io_info->pdBlock;
  559. u16 *pDevHandle = &io_info->devHandle;
  560. u32 logArm, rowMod, armQ, arm;
  561. if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
  562. instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
  563. do_invader = 1;
  564. /*Get row and span from io_info for Uneven Span IO.*/
  565. row = io_info->start_row;
  566. span = io_info->start_span;
  567. if (raid->level == 6) {
  568. logArm = get_arm_from_strip(instance, ld, stripRow, map);
  569. if (logArm == -1UL)
  570. return FALSE;
  571. rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
  572. armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;
  573. arm = armQ + 1 + logArm;
  574. if (arm >= SPAN_ROW_SIZE(map, ld, span))
  575. arm -= SPAN_ROW_SIZE(map, ld, span);
  576. physArm = (u8)arm;
  577. } else
  578. /* Calculate the arm */
  579. physArm = get_arm(instance, ld, span, stripRow, map);
  580. if (physArm == 0xFF)
  581. return FALSE;
  582. arRef = MR_LdSpanArrayGet(ld, span, map);
  583. pd = MR_ArPdGet(arRef, physArm, map);
  584. if (pd != MR_PD_INVALID)
  585. *pDevHandle = MR_PdDevHandleGet(pd, map);
  586. else {
  587. *pDevHandle = MR_PD_INVALID;
  588. if ((raid->level >= 5) &&
  589. (!do_invader || (do_invader &&
  590. (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
  591. pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
  592. else if (raid->level == 1) {
  593. pd = MR_ArPdGet(arRef, physArm + 1, map);
  594. if (pd != MR_PD_INVALID)
  595. *pDevHandle = MR_PdDevHandleGet(pd, map);
  596. }
  597. }
  598. *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
  599. pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
  600. physArm;
  601. return retval;
  602. }
  603. /*
  604. ******************************************************************************
  605. *
  606. * This routine calculates the arm, span and block for the specified stripe and
  607. * reference in stripe.
  608. *
  609. * Inputs :
  610. *
  611. * ld - Logical drive number
  612. * stripRow - Stripe number
  613. * stripRef - Reference in stripe
  614. *
  615. * Outputs :
  616. *
  617. * span - Span number
  618. * block - Absolute Block number in the physical disk
  619. */
  620. u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
  621. u16 stripRef, struct IO_REQUEST_INFO *io_info,
  622. struct RAID_CONTEXT *pRAID_Context,
  623. struct MR_FW_RAID_MAP_ALL *map)
  624. {
  625. struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
  626. u32 pd, arRef;
  627. u8 physArm, span;
  628. u64 row;
  629. u8 retval = TRUE;
  630. u8 do_invader = 0;
  631. u64 *pdBlock = &io_info->pdBlock;
  632. u16 *pDevHandle = &io_info->devHandle;
  633. if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
  634. instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
  635. do_invader = 1;
  636. row = mega_div64_32(stripRow, raid->rowDataSize);
  637. if (raid->level == 6) {
  638. /* logical arm within row */
  639. u32 logArm = mega_mod64(stripRow, raid->rowDataSize);
  640. u32 rowMod, armQ, arm;
  641. if (raid->rowSize == 0)
  642. return FALSE;
  643. /* get logical row mod */
  644. rowMod = mega_mod64(row, raid->rowSize);
  645. armQ = raid->rowSize-1-rowMod; /* index of Q drive */
  646. arm = armQ+1+logArm; /* data always logically follows Q */
  647. if (arm >= raid->rowSize) /* handle wrap condition */
  648. arm -= raid->rowSize;
  649. physArm = (u8)arm;
  650. } else {
  651. if (raid->modFactor == 0)
  652. return FALSE;
  653. physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow,
  654. raid->modFactor),
  655. map);
  656. }
  657. if (raid->spanDepth == 1) {
  658. span = 0;
  659. *pdBlock = row << raid->stripeShift;
  660. } else {
  661. span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map);
  662. if (span == SPAN_INVALID)
  663. return FALSE;
  664. }
  665. /* Get the array on which this span is present */
  666. arRef = MR_LdSpanArrayGet(ld, span, map);
  667. pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
  668. if (pd != MR_PD_INVALID)
  669. /* Get dev handle from Pd. */
  670. *pDevHandle = MR_PdDevHandleGet(pd, map);
  671. else {
  672. *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
  673. if ((raid->level >= 5) &&
  674. (!do_invader || (do_invader &&
  675. (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
  676. pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
  677. else if (raid->level == 1) {
  678. /* Get alternate Pd. */
  679. pd = MR_ArPdGet(arRef, physArm + 1, map);
  680. if (pd != MR_PD_INVALID)
  681. /* Get dev handle from Pd */
  682. *pDevHandle = MR_PdDevHandleGet(pd, map);
  683. }
  684. }
  685. *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
  686. pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
  687. physArm;
  688. return retval;
  689. }
  690. /*
  691. ******************************************************************************
  692. *
  693. * MR_BuildRaidContext function
  694. *
  695. * This function will initiate command processing. The start/end row and strip
  696. * information is calculated then the lock is acquired.
  697. * This function will return 0 if region lock was acquired OR return num strips
  698. */
  699. u8
  700. MR_BuildRaidContext(struct megasas_instance *instance,
  701. struct IO_REQUEST_INFO *io_info,
  702. struct RAID_CONTEXT *pRAID_Context,
  703. struct MR_FW_RAID_MAP_ALL *map)
  704. {
  705. struct MR_LD_RAID *raid;
  706. u32 ld, stripSize, stripe_mask;
  707. u64 endLba, endStrip, endRow, start_row, start_strip;
  708. u64 regStart;
  709. u32 regSize;
  710. u8 num_strips, numRows;
  711. u16 ref_in_start_stripe, ref_in_end_stripe;
  712. u64 ldStartBlock;
  713. u32 numBlocks, ldTgtId;
  714. u8 isRead;
  715. u8 retval = 0;
  716. u8 startlba_span = SPAN_INVALID;
  717. u64 *pdBlock = &io_info->pdBlock;
  718. ldStartBlock = io_info->ldStartBlock;
  719. numBlocks = io_info->numBlocks;
  720. ldTgtId = io_info->ldTgtId;
  721. isRead = io_info->isRead;
  722. io_info->IoforUnevenSpan = 0;
  723. io_info->start_span = SPAN_INVALID;
  724. ld = MR_TargetIdToLdGet(ldTgtId, map);
  725. raid = MR_LdRaidGet(ld, map);
  726. /*
  727. * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
  728. * return FALSE
  729. */
  730. if (raid->rowDataSize == 0) {
  731. if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
  732. return FALSE;
  733. else if (instance->UnevenSpanSupport) {
  734. io_info->IoforUnevenSpan = 1;
  735. } else {
  736. dev_info(&instance->pdev->dev,
  737. "raid->rowDataSize is 0, but has SPAN[0]"
  738. "rowDataSize = 0x%0x,"
  739. "but there is _NO_ UnevenSpanSupport\n",
  740. MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
  741. return FALSE;
  742. }
  743. }
  744. stripSize = 1 << raid->stripeShift;
  745. stripe_mask = stripSize-1;
  746. /*
  747. * calculate starting row and stripe, and number of strips and rows
  748. */
  749. start_strip = ldStartBlock >> raid->stripeShift;
  750. ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);
  751. endLba = ldStartBlock + numBlocks - 1;
  752. ref_in_end_stripe = (u16)(endLba & stripe_mask);
  753. endStrip = endLba >> raid->stripeShift;
  754. num_strips = (u8)(endStrip - start_strip + 1); /* End strip */
  755. if (io_info->IoforUnevenSpan) {
  756. start_row = get_row_from_strip(instance, ld, start_strip, map);
  757. endRow = get_row_from_strip(instance, ld, endStrip, map);
  758. if (start_row == -1ULL || endRow == -1ULL) {
  759. dev_info(&instance->pdev->dev, "return from %s %d."
  760. "Send IO w/o region lock.\n",
  761. __func__, __LINE__);
  762. return FALSE;
  763. }
  764. if (raid->spanDepth == 1) {
  765. startlba_span = 0;
  766. *pdBlock = start_row << raid->stripeShift;
  767. } else
  768. startlba_span = (u8)mr_spanset_get_span_block(instance,
  769. ld, start_row, pdBlock, map);
  770. if (startlba_span == SPAN_INVALID) {
  771. dev_info(&instance->pdev->dev, "return from %s %d"
  772. "for row 0x%llx,start strip %llx"
  773. "endSrip %llx\n", __func__, __LINE__,
  774. (unsigned long long)start_row,
  775. (unsigned long long)start_strip,
  776. (unsigned long long)endStrip);
  777. return FALSE;
  778. }
  779. io_info->start_span = startlba_span;
  780. io_info->start_row = start_row;
  781. #if SPAN_DEBUG
  782. dev_dbg(&instance->pdev->dev, "Check Span number from %s %d"
  783. "for row 0x%llx, start strip 0x%llx end strip 0x%llx"
  784. " span 0x%x\n", __func__, __LINE__,
  785. (unsigned long long)start_row,
  786. (unsigned long long)start_strip,
  787. (unsigned long long)endStrip, startlba_span);
  788. dev_dbg(&instance->pdev->dev, "start_row 0x%llx endRow 0x%llx"
  789. "Start span 0x%x\n", (unsigned long long)start_row,
  790. (unsigned long long)endRow, startlba_span);
  791. #endif
  792. } else {
  793. start_row = mega_div64_32(start_strip, raid->rowDataSize);
  794. endRow = mega_div64_32(endStrip, raid->rowDataSize);
  795. }
  796. numRows = (u8)(endRow - start_row + 1);
  797. /*
  798. * calculate region info.
  799. */
  800. /* assume region is at the start of the first row */
  801. regStart = start_row << raid->stripeShift;
  802. /* assume this IO needs the full row - we'll adjust if not true */
  803. regSize = stripSize;
  804. /* Check if we can send this I/O via FastPath */
  805. if (raid->capability.fpCapable) {
  806. if (isRead)
  807. io_info->fpOkForIo = (raid->capability.fpReadCapable &&
  808. ((num_strips == 1) ||
  809. raid->capability.
  810. fpReadAcrossStripe));
  811. else
  812. io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
  813. ((num_strips == 1) ||
  814. raid->capability.
  815. fpWriteAcrossStripe));
  816. } else
  817. io_info->fpOkForIo = FALSE;
  818. if (numRows == 1) {
  819. /* single-strip IOs can always lock only the data needed */
  820. if (num_strips == 1) {
  821. regStart += ref_in_start_stripe;
  822. regSize = numBlocks;
  823. }
  824. /* multi-strip IOs always need to full stripe locked */
  825. } else if (io_info->IoforUnevenSpan == 0) {
  826. /*
  827. * For Even span region lock optimization.
  828. * If the start strip is the last in the start row
  829. */
  830. if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
  831. regStart += ref_in_start_stripe;
  832. /* initialize count to sectors from startref to end
  833. of strip */
  834. regSize = stripSize - ref_in_start_stripe;
  835. }
  836. /* add complete rows in the middle of the transfer */
  837. if (numRows > 2)
  838. regSize += (numRows-2) << raid->stripeShift;
  839. /* if IO ends within first strip of last row*/
  840. if (endStrip == endRow*raid->rowDataSize)
  841. regSize += ref_in_end_stripe+1;
  842. else
  843. regSize += stripSize;
  844. } else {
  845. /*
  846. * For Uneven span region lock optimization.
  847. * If the start strip is the last in the start row
  848. */
  849. if (start_strip == (get_strip_from_row(instance, ld, start_row, map) +
  850. SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
  851. regStart += ref_in_start_stripe;
  852. /* initialize count to sectors from
  853. * startRef to end of strip
  854. */
  855. regSize = stripSize - ref_in_start_stripe;
  856. }
  857. /* Add complete rows in the middle of the transfer*/
  858. if (numRows > 2)
  859. /* Add complete rows in the middle of the transfer*/
  860. regSize += (numRows-2) << raid->stripeShift;
  861. /* if IO ends within first strip of last row */
  862. if (endStrip == get_strip_from_row(instance, ld, endRow, map))
  863. regSize += ref_in_end_stripe + 1;
  864. else
  865. regSize += stripSize;
  866. }
  867. pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
  868. if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
  869. (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
  870. pRAID_Context->regLockFlags = (isRead) ?
  871. raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
  872. else
  873. pRAID_Context->regLockFlags = (isRead) ?
  874. REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
  875. pRAID_Context->VirtualDiskTgtId = raid->targetId;
  876. pRAID_Context->regLockRowLBA = regStart;
  877. pRAID_Context->regLockLength = regSize;
  878. pRAID_Context->configSeqNum = raid->seqNum;
  879. /*Get Phy Params only if FP capable, or else leave it to MR firmware
  880. to do the calculation.*/
  881. if (io_info->fpOkForIo) {
  882. retval = io_info->IoforUnevenSpan ?
  883. mr_spanset_get_phy_params(instance, ld,
  884. start_strip, ref_in_start_stripe,
  885. io_info, pRAID_Context, map) :
  886. MR_GetPhyParams(instance, ld, start_strip,
  887. ref_in_start_stripe, io_info,
  888. pRAID_Context, map);
  889. /* If IO on an invalid Pd, then FP is not possible.*/
  890. if (io_info->devHandle == MR_PD_INVALID)
  891. io_info->fpOkForIo = FALSE;
  892. return retval;
  893. } else if (isRead) {
  894. uint stripIdx;
  895. for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
  896. retval = io_info->IoforUnevenSpan ?
  897. mr_spanset_get_phy_params(instance, ld,
  898. start_strip + stripIdx,
  899. ref_in_start_stripe, io_info,
  900. pRAID_Context, map) :
  901. MR_GetPhyParams(instance, ld,
  902. start_strip + stripIdx, ref_in_start_stripe,
  903. io_info, pRAID_Context, map);
  904. if (!retval)
  905. return TRUE;
  906. }
  907. }
  908. #if SPAN_DEBUG
  909. /* Just for testing what arm we get for strip.*/
  910. if (io_info->IoforUnevenSpan)
  911. get_arm_from_strip(instance, ld, start_strip, map);
  912. #endif
  913. return TRUE;
  914. }
  915. /*
  916. ******************************************************************************
  917. *
  918. * This routine pepare spanset info from Valid Raid map and store it into
  919. * local copy of ldSpanInfo per instance data structure.
  920. *
  921. * Inputs :
  922. * map - LD map
  923. * ldSpanInfo - ldSpanInfo per HBA instance
  924. *
  925. */
  926. void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
  927. PLD_SPAN_INFO ldSpanInfo)
  928. {
  929. u8 span, count;
  930. u32 element, span_row_width;
  931. u64 span_row;
  932. struct MR_LD_RAID *raid;
  933. LD_SPAN_SET *span_set, *span_set_prev;
  934. struct MR_QUAD_ELEMENT *quad;
  935. int ldCount;
  936. u16 ld;
  937. for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
  938. ld = MR_TargetIdToLdGet(ldCount, map);
  939. if (ld >= MAX_LOGICAL_DRIVES)
  940. continue;
  941. raid = MR_LdRaidGet(ld, map);
  942. for (element = 0; element < MAX_QUAD_DEPTH; element++) {
  943. for (span = 0; span < raid->spanDepth; span++) {
  944. if (map->raidMap.ldSpanMap[ld].spanBlock[span].
  945. block_span_info.noElements <
  946. element + 1)
  947. continue;
  948. span_set = &(ldSpanInfo[ld].span_set[element]);
  949. quad = &map->raidMap.ldSpanMap[ld].
  950. spanBlock[span].block_span_info.
  951. quad[element];
  952. span_set->diff = quad->diff;
  953. for (count = 0, span_row_width = 0;
  954. count < raid->spanDepth; count++) {
  955. if (map->raidMap.ldSpanMap[ld].
  956. spanBlock[count].
  957. block_span_info.
  958. noElements >= element + 1) {
  959. span_set->strip_offset[count] =
  960. span_row_width;
  961. span_row_width +=
  962. MR_LdSpanPtrGet
  963. (ld, count, map)->spanRowDataSize;
  964. printk(KERN_INFO "megasas:"
  965. "span %x rowDataSize %x\n",
  966. count, MR_LdSpanPtrGet
  967. (ld, count, map)->spanRowDataSize);
  968. }
  969. }
  970. span_set->span_row_data_width = span_row_width;
  971. span_row = mega_div64_32(((quad->logEnd -
  972. quad->logStart) + quad->diff),
  973. quad->diff);
  974. if (element == 0) {
  975. span_set->log_start_lba = 0;
  976. span_set->log_end_lba =
  977. ((span_row << raid->stripeShift)
  978. * span_row_width) - 1;
  979. span_set->span_row_start = 0;
  980. span_set->span_row_end = span_row - 1;
  981. span_set->data_strip_start = 0;
  982. span_set->data_strip_end =
  983. (span_row * span_row_width) - 1;
  984. span_set->data_row_start = 0;
  985. span_set->data_row_end =
  986. (span_row * quad->diff) - 1;
  987. } else {
  988. span_set_prev = &(ldSpanInfo[ld].
  989. span_set[element - 1]);
  990. span_set->log_start_lba =
  991. span_set_prev->log_end_lba + 1;
  992. span_set->log_end_lba =
  993. span_set->log_start_lba +
  994. ((span_row << raid->stripeShift)
  995. * span_row_width) - 1;
  996. span_set->span_row_start =
  997. span_set_prev->span_row_end + 1;
  998. span_set->span_row_end =
  999. span_set->span_row_start + span_row - 1;
  1000. span_set->data_strip_start =
  1001. span_set_prev->data_strip_end + 1;
  1002. span_set->data_strip_end =
  1003. span_set->data_strip_start +
  1004. (span_row * span_row_width) - 1;
  1005. span_set->data_row_start =
  1006. span_set_prev->data_row_end + 1;
  1007. span_set->data_row_end =
  1008. span_set->data_row_start +
  1009. (span_row * quad->diff) - 1;
  1010. }
  1011. break;
  1012. }
  1013. if (span == raid->spanDepth)
  1014. break;
  1015. }
  1016. }
  1017. #if SPAN_DEBUG
  1018. getSpanInfo(map, ldSpanInfo);
  1019. #endif
  1020. }
  1021. void
  1022. mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
  1023. struct LD_LOAD_BALANCE_INFO *lbInfo)
  1024. {
  1025. int ldCount;
  1026. u16 ld;
  1027. struct MR_LD_RAID *raid;
  1028. for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
  1029. ld = MR_TargetIdToLdGet(ldCount, map);
  1030. if (ld >= MAX_LOGICAL_DRIVES) {
  1031. lbInfo[ldCount].loadBalanceFlag = 0;
  1032. continue;
  1033. }
  1034. raid = MR_LdRaidGet(ld, map);
  1035. /* Two drive Optimal RAID 1 */
  1036. if ((raid->level == 1) && (raid->rowSize == 2) &&
  1037. (raid->spanDepth == 1) && raid->ldState ==
  1038. MR_LD_STATE_OPTIMAL) {
  1039. u32 pd, arRef;
  1040. lbInfo[ldCount].loadBalanceFlag = 1;
  1041. /* Get the array on which this span is present */
  1042. arRef = MR_LdSpanArrayGet(ld, 0, map);
  1043. /* Get the Pd */
  1044. pd = MR_ArPdGet(arRef, 0, map);
  1045. /* Get dev handle from Pd */
  1046. lbInfo[ldCount].raid1DevHandle[0] =
  1047. MR_PdDevHandleGet(pd, map);
  1048. /* Get the Pd */
  1049. pd = MR_ArPdGet(arRef, 1, map);
  1050. /* Get the dev handle from Pd */
  1051. lbInfo[ldCount].raid1DevHandle[1] =
  1052. MR_PdDevHandleGet(pd, map);
  1053. } else
  1054. lbInfo[ldCount].loadBalanceFlag = 0;
  1055. }
  1056. }
  1057. u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block,
  1058. u32 count)
  1059. {
  1060. u16 pend0, pend1;
  1061. u64 diff0, diff1;
  1062. u8 bestArm;
  1063. /* get the pending cmds for the data and mirror arms */
  1064. pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
  1065. pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
  1066. /* Determine the disk whose head is nearer to the req. block */
  1067. diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
  1068. diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
  1069. bestArm = (diff0 <= diff1 ? 0 : 1);
  1070. /*Make balance count from 16 to 4 to keep driver in sync with Firmware*/
  1071. if ((bestArm == arm && pend0 > pend1 + 4) ||
  1072. (bestArm != arm && pend1 > pend0 + 4))
  1073. bestArm ^= 1;
  1074. /* Update the last accessed block on the correct pd */
  1075. lbInfo->last_accessed_block[bestArm] = block + count - 1;
  1076. return bestArm;
  1077. }
  1078. u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
  1079. struct IO_REQUEST_INFO *io_info)
  1080. {
  1081. u8 arm, old_arm;
  1082. u16 devHandle;
  1083. old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
  1084. /* get best new arm */
  1085. arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock,
  1086. io_info->numBlocks);
  1087. devHandle = lbInfo->raid1DevHandle[arm];
  1088. atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
  1089. return devHandle;
  1090. }