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