1 /* 2 * Copyright (c) 2014, LSI Corp. 3 * All rights reserved. 4 * Author: Marian Choy 5 * Support: freebsdraid@lsi.com 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of the <ORGANIZATION> nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 * 34 * The views and conclusions contained in the software and documentation 35 * are those of the authors and should not be interpreted as representing 36 * official policies,either expressed or implied, of the FreeBSD Project. 37 * 38 * Send feedback to: <megaraidfbsd@lsi.com> 39 * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 40 * ATTN: MegaRaid FreeBSD 41 * 42 */ 43 44 #include <sys/cdefs.h> 45 __FBSDID("$FreeBSD$"); 46 47 #include <dev/mrsas/mrsas.h> 48 49 #include <cam/cam.h> 50 #include <cam/cam_ccb.h> 51 #include <cam/cam_sim.h> 52 #include <cam/cam_xpt_sim.h> 53 #include <cam/cam_debug.h> 54 #include <cam/cam_periph.h> 55 #include <cam/cam_xpt_periph.h> 56 57 58 /* 59 * Function prototypes 60 */ 61 u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc); 62 u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, 63 u_int64_t block, u_int32_t count); 64 u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc, 65 struct IO_REQUEST_INFO *io_info, 66 RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map); 67 u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld, 68 u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, 69 RAID_CONTEXT *pRAID_Context, 70 MR_FW_RAID_MAP_ALL *map); 71 u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); 72 u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); 73 u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); 74 u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, 75 struct IO_REQUEST_INFO *io_info); 76 u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor); 77 u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk, 78 MR_FW_RAID_MAP_ALL *map, int *div_error); 79 u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor); 80 void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, 81 PLD_LOAD_BALANCE_INFO lbInfo); 82 void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, 83 u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb, 84 MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, 85 u_int32_t ld_block_size); 86 static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, 87 MR_FW_RAID_MAP_ALL *map); 88 static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map); 89 static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, 90 MR_FW_RAID_MAP_ALL *map); 91 static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, 92 MR_FW_RAID_MAP_ALL *map); 93 static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, 94 MR_FW_RAID_MAP_ALL *map); 95 static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, 96 MR_FW_RAID_MAP_ALL *map); 97 MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); 98 99 /* 100 * Spanset related function prototypes 101 * Added for PRL11 configuration (Uneven span support) 102 */ 103 void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo); 104 static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, 105 u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, 106 RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map); 107 static u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld, 108 u_int64_t strip, MR_FW_RAID_MAP_ALL *map); 109 static u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, 110 u_int32_t ld, u_int64_t row, u_int64_t *span_blk, 111 MR_FW_RAID_MAP_ALL *map, int *div_error); 112 static u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, 113 u_int64_t stripe, MR_FW_RAID_MAP_ALL *map); 114 115 116 /* 117 * Spanset related defines 118 * Added for PRL11 configuration(Uneven span support) 119 */ 120 #define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize 121 #define SPAN_ROW_DATA_SIZE(map_, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize 122 #define SPAN_INVALID 0xff 123 #define SPAN_DEBUG 0 124 125 /* 126 * Related Defines 127 */ 128 129 typedef u_int64_t REGION_KEY; 130 typedef u_int32_t REGION_LEN; 131 132 #define MR_LD_STATE_OPTIMAL 3 133 #define FALSE 0 134 #define TRUE 1 135 136 137 /* 138 * Related Macros 139 */ 140 141 #define ABS_DIFF(a,b) ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) ) 142 143 #define swap32(x) \ 144 ((unsigned int)( \ 145 (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ 146 (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ 147 (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ 148 (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) 149 150 151 /* 152 * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor. 153 * Assumes a check for a divisor of zero is not possible. 154 * 155 * @param dividend : Dividend 156 * @param divisor : Divisor 157 * @return remainder 158 */ 159 160 #define mega_mod64(dividend, divisor) ({ \ 161 int remainder; \ 162 remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \ 163 remainder;}) 164 165 #define mega_div64_32(dividend, divisor) ({ \ 166 int quotient; \ 167 quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \ 168 quotient;}) 169 170 171 /* 172 * Various RAID map access functions. These functions access the various 173 * parts of the RAID map and returns the appropriate parameters. 174 */ 175 176 MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) 177 { 178 return (&map->raidMap.ldSpanMap[ld].ldRaid); 179 } 180 181 u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) 182 { 183 return (map->raidMap.ldSpanMap[ld].ldRaid.targetId); 184 } 185 186 static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map) 187 { 188 return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef; 189 } 190 191 static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_FW_RAID_MAP_ALL *map) 192 { 193 return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; 194 } 195 196 static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map) 197 { 198 return map->raidMap.devHndlInfo[pd].curDevHdl; 199 } 200 201 static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_FW_RAID_MAP_ALL *map) 202 { 203 return map->raidMap.arMapInfo[ar].pd[arm]; 204 } 205 206 static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map) 207 { 208 return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; 209 } 210 211 static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) 212 { 213 return &map->raidMap.ldSpanMap[ld].spanBlock[0]; 214 } 215 216 u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map) 217 { 218 return map->raidMap.ldTgtIdToLd[ldTgtId]; 219 } 220 221 u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map) 222 { 223 MR_LD_RAID *raid; 224 u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE; 225 226 ld = MR_TargetIdToLdGet(ldTgtId, map); 227 228 /* 229 * Check if logical drive was removed. 230 */ 231 if (ld >= MAX_LOGICAL_DRIVES) 232 return ldBlockSize; 233 234 raid = MR_LdRaidGet(ld, map); 235 ldBlockSize = raid->logicalBlockLength; 236 if (!ldBlockSize) 237 ldBlockSize = MRSAS_SCSIBLOCKSIZE; 238 239 return ldBlockSize; 240 } 241 242 /** 243 * MR_ValidateMapInfo: Validate RAID map 244 * input: Adapter instance soft state 245 * 246 * This function checks and validates the loaded RAID map. It returns 0 if 247 * successful, and 1 otherwise. 248 */ 249 u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc) 250 { 251 if (!sc) { 252 return 1; 253 } 254 uint32_t total_map_sz; 255 MR_FW_RAID_MAP_ALL *map = sc->raidmap_mem[(sc->map_id & 1)]; 256 MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap; 257 PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span; 258 259 total_map_sz = (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) + 260 (sizeof(MR_LD_SPAN_MAP) * pFwRaidMap->ldCount)); 261 262 if (pFwRaidMap->totalSize != total_map_sz) { 263 device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", total_map_sz); 264 device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP)); 265 device_printf(sc->mrsas_dev, "pFwRaidMap->totalSize=%x\n", pFwRaidMap->totalSize); 266 return 1; 267 } 268 269 if (sc->UnevenSpanSupport) { 270 mr_update_span_set(map, ldSpanInfo); 271 } 272 273 mrsas_update_load_balance_params(map, sc->load_balance_info); 274 275 return 0; 276 } 277 278 /* 279 * ****************************************************************************** 280 * 281 * Function to print info about span set created in driver from FW raid map 282 * 283 * Inputs : 284 * map - LD map 285 * ldSpanInfo - ldSpanInfo per HBA instance 286 * 287 * 288 * */ 289 #if SPAN_DEBUG 290 static int getSpanInfo(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo) 291 { 292 293 u_int8_t span; 294 u_int32_t element; 295 MR_LD_RAID *raid; 296 LD_SPAN_SET *span_set; 297 MR_QUAD_ELEMENT *quad; 298 int ldCount; 299 u_int16_t ld; 300 301 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) 302 { 303 ld = MR_TargetIdToLdGet(ldCount, map); 304 if (ld >= MAX_LOGICAL_DRIVES) { 305 continue; 306 } 307 raid = MR_LdRaidGet(ld, map); 308 printf("LD %x: span_depth=%x\n", ld, raid->spanDepth); 309 for (span=0; span<raid->spanDepth; span++) 310 printf("Span=%x, number of quads=%x\n", span, 311 map->raidMap.ldSpanMap[ld].spanBlock[span]. 312 block_span_info.noElements); 313 for (element=0; element < MAX_QUAD_DEPTH; element++) { 314 span_set = &(ldSpanInfo[ld].span_set[element]); 315 if (span_set->span_row_data_width == 0) break; 316 317 printf(" Span Set %x: width=%x, diff=%x\n", element, 318 (unsigned int)span_set->span_row_data_width, 319 (unsigned int)span_set->diff); 320 printf(" logical LBA start=0x%08lx, end=0x%08lx\n", 321 (long unsigned int)span_set->log_start_lba, 322 (long unsigned int)span_set->log_end_lba); 323 printf(" span row start=0x%08lx, end=0x%08lx\n", 324 (long unsigned int)span_set->span_row_start, 325 (long unsigned int)span_set->span_row_end); 326 printf(" data row start=0x%08lx, end=0x%08lx\n", 327 (long unsigned int)span_set->data_row_start, 328 (long unsigned int)span_set->data_row_end); 329 printf(" data strip start=0x%08lx, end=0x%08lx\n", 330 (long unsigned int)span_set->data_strip_start, 331 (long unsigned int)span_set->data_strip_end); 332 333 for (span=0; span<raid->spanDepth; span++) { 334 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 335 block_span_info.noElements >=element+1){ 336 quad = &map->raidMap.ldSpanMap[ld]. 337 spanBlock[span].block_span_info. 338 quad[element]; 339 printf(" Span=%x, Quad=%x, diff=%x\n", span, 340 element, quad->diff); 341 printf(" offset_in_span=0x%08lx\n", 342 (long unsigned int)quad->offsetInSpan); 343 printf(" logical start=0x%08lx, end=0x%08lx\n", 344 (long unsigned int)quad->logStart, 345 (long unsigned int)quad->logEnd); 346 } 347 } 348 } 349 } 350 return 0; 351 } 352 #endif 353 /* 354 ****************************************************************************** 355 * 356 * This routine calculates the Span block for given row using spanset. 357 * 358 * Inputs : 359 * instance - HBA instance 360 * ld - Logical drive number 361 * row - Row number 362 * map - LD map 363 * 364 * Outputs : 365 * 366 * span - Span number 367 * block - Absolute Block number in the physical disk 368 * div_error - Devide error code. 369 */ 370 371 u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row, 372 u_int64_t *span_blk, MR_FW_RAID_MAP_ALL *map, int *div_error) 373 { 374 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 375 LD_SPAN_SET *span_set; 376 MR_QUAD_ELEMENT *quad; 377 u_int32_t span, info; 378 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; 379 380 for (info=0; info < MAX_QUAD_DEPTH; info++) { 381 span_set = &(ldSpanInfo[ld].span_set[info]); 382 383 if (span_set->span_row_data_width == 0) break; 384 if (row > span_set->data_row_end) continue; 385 386 for (span=0; span<raid->spanDepth; span++) 387 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 388 block_span_info.noElements >= info+1) { 389 quad = &map->raidMap.ldSpanMap[ld]. 390 spanBlock[span]. 391 block_span_info.quad[info]; 392 if (quad->diff == 0) { 393 *div_error = 1; 394 return span; 395 } 396 if ( quad->logStart <= row && 397 row <= quad->logEnd && 398 (mega_mod64(row - quad->logStart, 399 quad->diff)) == 0 ) { 400 if (span_blk != NULL) { 401 u_int64_t blk; 402 blk = mega_div64_32 403 ((row - quad->logStart), 404 quad->diff); 405 blk = (blk + quad->offsetInSpan) 406 << raid->stripeShift; 407 *span_blk = blk; 408 } 409 return span; 410 } 411 } 412 } 413 return SPAN_INVALID; 414 } 415 416 /* 417 ****************************************************************************** 418 * 419 * This routine calculates the row for given strip using spanset. 420 * 421 * Inputs : 422 * instance - HBA instance 423 * ld - Logical drive number 424 * Strip - Strip 425 * map - LD map 426 * 427 * Outputs : 428 * 429 * row - row associated with strip 430 */ 431 432 static u_int64_t get_row_from_strip(struct mrsas_softc *sc, 433 u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map) 434 { 435 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 436 LD_SPAN_SET *span_set; 437 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; 438 u_int32_t info, strip_offset, span, span_offset; 439 u_int64_t span_set_Strip, span_set_Row; 440 441 for (info=0; info < MAX_QUAD_DEPTH; info++) { 442 span_set = &(ldSpanInfo[ld].span_set[info]); 443 444 if (span_set->span_row_data_width == 0) break; 445 if (strip > span_set->data_strip_end) continue; 446 447 span_set_Strip = strip - span_set->data_strip_start; 448 strip_offset = mega_mod64(span_set_Strip, 449 span_set->span_row_data_width); 450 span_set_Row = mega_div64_32(span_set_Strip, 451 span_set->span_row_data_width) * span_set->diff; 452 for (span=0,span_offset=0; span<raid->spanDepth; span++) 453 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 454 block_span_info.noElements >=info+1) { 455 if (strip_offset >= 456 span_set->strip_offset[span]) 457 span_offset++; 458 else 459 break; 460 } 461 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx " 462 "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip, 463 (unsigned long long)span_set_Strip, 464 (unsigned long long)span_set_Row, 465 (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset); 466 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip, 467 (unsigned long long) span_set->data_row_start + 468 (unsigned long long) span_set_Row + (span_offset - 1)); 469 return (span_set->data_row_start + span_set_Row + (span_offset - 1)); 470 } 471 return -1LLU; 472 } 473 474 475 /* 476 ****************************************************************************** 477 * 478 * This routine calculates the Start Strip for given row using spanset. 479 * 480 * Inputs : 481 * instance - HBA instance 482 * ld - Logical drive number 483 * row - Row number 484 * map - LD map 485 * 486 * Outputs : 487 * 488 * Strip - Start strip associated with row 489 */ 490 491 static u_int64_t get_strip_from_row(struct mrsas_softc *sc, 492 u_int32_t ld, u_int64_t row, MR_FW_RAID_MAP_ALL *map) 493 { 494 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 495 LD_SPAN_SET *span_set; 496 MR_QUAD_ELEMENT *quad; 497 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; 498 u_int32_t span, info; 499 u_int64_t strip; 500 501 for (info=0; info<MAX_QUAD_DEPTH; info++) { 502 span_set = &(ldSpanInfo[ld].span_set[info]); 503 504 if (span_set->span_row_data_width == 0) break; 505 if (row > span_set->data_row_end) continue; 506 507 for (span=0; span<raid->spanDepth; span++) 508 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 509 block_span_info.noElements >=info+1) { 510 quad = &map->raidMap.ldSpanMap[ld]. 511 spanBlock[span].block_span_info.quad[info]; 512 if ( quad->logStart <= row && 513 row <= quad->logEnd && 514 mega_mod64((row - quad->logStart), 515 quad->diff) == 0 ) { 516 strip = mega_div64_32 517 (((row - span_set->data_row_start) 518 - quad->logStart), 519 quad->diff); 520 strip *= span_set->span_row_data_width; 521 strip += span_set->data_strip_start; 522 strip += span_set->strip_offset[span]; 523 return strip; 524 } 525 } 526 } 527 mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid " 528 "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row); 529 return -1; 530 } 531 532 /* 533 ****************************************************************************** 534 * 535 * This routine calculates the Physical Arm for given strip using spanset. 536 * 537 * Inputs : 538 * instance - HBA instance 539 * ld - Logical drive number 540 * strip - Strip 541 * map - LD map 542 * 543 * Outputs : 544 * 545 * Phys Arm - Phys Arm associated with strip 546 */ 547 548 static u_int32_t get_arm_from_strip(struct mrsas_softc *sc, 549 u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map) 550 { 551 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 552 LD_SPAN_SET *span_set; 553 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; 554 u_int32_t info, strip_offset, span, span_offset; 555 556 for (info=0; info<MAX_QUAD_DEPTH; info++) { 557 span_set = &(ldSpanInfo[ld].span_set[info]); 558 559 if (span_set->span_row_data_width == 0) break; 560 if (strip > span_set->data_strip_end) continue; 561 562 strip_offset = (u_int32_t)mega_mod64 563 ((strip - span_set->data_strip_start), 564 span_set->span_row_data_width); 565 566 for (span=0,span_offset=0; span<raid->spanDepth; span++) 567 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 568 block_span_info.noElements >=info+1) { 569 if (strip_offset >= 570 span_set->strip_offset[span]) 571 span_offset = 572 span_set->strip_offset[span]; 573 else 574 break; 575 } 576 mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: " 577 " for ld=0x%x strip=0x%lx arm is 0x%x\n", ld, 578 (long unsigned int)strip, (strip_offset - span_offset)); 579 return (strip_offset - span_offset); 580 } 581 582 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm" 583 " for ld=%x strip=%lx\n", ld, (long unsigned int)strip); 584 585 return -1; 586 } 587 588 589 /* This Function will return Phys arm */ 590 u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe, 591 MR_FW_RAID_MAP_ALL *map) 592 { 593 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 594 /* Need to check correct default value */ 595 u_int32_t arm = 0; 596 597 switch (raid->level) { 598 case 0: 599 case 5: 600 case 6: 601 arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span)); 602 break; 603 case 1: 604 // start with logical arm 605 arm = get_arm_from_strip(sc, ld, stripe, map); 606 arm *= 2; 607 break; 608 609 } 610 611 return arm; 612 } 613 614 /* 615 ****************************************************************************** 616 * 617 * This routine calculates the arm, span and block for the specified stripe and 618 * reference in stripe using spanset 619 * 620 * Inputs : 621 * 622 * ld - Logical drive number 623 * stripRow - Stripe number 624 * stripRef - Reference in stripe 625 * 626 * Outputs : 627 * 628 * span - Span number 629 * block - Absolute Block number in the physical disk 630 */ 631 static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow, 632 u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, 633 RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) 634 { 635 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 636 u_int32_t pd, arRef; 637 u_int8_t physArm, span; 638 u_int64_t row; 639 u_int8_t retval = TRUE; 640 u_int64_t *pdBlock = &io_info->pdBlock; 641 u_int16_t *pDevHandle = &io_info->devHandle; 642 u_int32_t logArm, rowMod, armQ, arm; 643 u_int8_t do_invader = 0; 644 645 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) 646 do_invader = 1; 647 648 // Get row and span from io_info for Uneven Span IO. 649 row = io_info->start_row; 650 span = io_info->start_span; 651 652 653 if (raid->level == 6) { 654 logArm = get_arm_from_strip(sc, ld, stripRow, map); 655 rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span)); 656 armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod; 657 arm = armQ + 1 + logArm; 658 if (arm >= SPAN_ROW_SIZE(map, ld, span)) 659 arm -= SPAN_ROW_SIZE(map ,ld ,span); 660 physArm = (u_int8_t)arm; 661 } else 662 // Calculate the arm 663 physArm = get_arm(sc, ld, span, stripRow, map); 664 665 666 arRef = MR_LdSpanArrayGet(ld, span, map); 667 pd = MR_ArPdGet(arRef, physArm, map); 668 669 if (pd != MR_PD_INVALID) 670 *pDevHandle = MR_PdDevHandleGet(pd, map); 671 else { 672 *pDevHandle = MR_PD_INVALID; 673 if ((raid->level >= 5) && ((!do_invader) || (do_invader && 674 raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) 675 pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; 676 else if (raid->level == 1) { 677 pd = MR_ArPdGet(arRef, physArm + 1, map); 678 if (pd != MR_PD_INVALID) 679 *pDevHandle = MR_PdDevHandleGet(pd, map); 680 } 681 } 682 683 *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; 684 pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 685 return retval; 686 } 687 688 /** 689 * MR_BuildRaidContext: Set up Fast path RAID context 690 * 691 * This function will initiate command processing. The start/end row 692 * and strip information is calculated then the lock is acquired. 693 * This function will return 0 if region lock was acquired OR return 694 * num strips. 695 */ 696 u_int8_t 697 MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info, 698 RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) 699 { 700 MR_LD_RAID *raid; 701 u_int32_t ld, stripSize, stripe_mask; 702 u_int64_t endLba, endStrip, endRow, start_row, start_strip; 703 REGION_KEY regStart; 704 REGION_LEN regSize; 705 u_int8_t num_strips, numRows; 706 u_int16_t ref_in_start_stripe, ref_in_end_stripe; 707 u_int64_t ldStartBlock; 708 u_int32_t numBlocks, ldTgtId; 709 u_int8_t isRead, stripIdx; 710 u_int8_t retval = 0; 711 u_int8_t startlba_span = SPAN_INVALID; 712 u_int64_t *pdBlock = &io_info->pdBlock; 713 int error_code = 0; 714 715 ldStartBlock = io_info->ldStartBlock; 716 numBlocks = io_info->numBlocks; 717 ldTgtId = io_info->ldTgtId; 718 isRead = io_info->isRead; 719 720 io_info->IoforUnevenSpan = 0; 721 io_info->start_span = SPAN_INVALID; 722 723 ld = MR_TargetIdToLdGet(ldTgtId, map); 724 raid = MR_LdRaidGet(ld, map); 725 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 (sc->UnevenSpanSupport) { 734 io_info->IoforUnevenSpan = 1; 735 } 736 else { 737 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x," 738 " but there is _NO_ UnevenSpanSupport\n", 739 MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); 740 return FALSE; 741 } 742 } 743 stripSize = 1 << raid->stripeShift; 744 stripe_mask = stripSize-1; 745 /* 746 * calculate starting row and stripe, and number of strips and rows 747 */ 748 start_strip = ldStartBlock >> raid->stripeShift; 749 ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask); 750 endLba = ldStartBlock + numBlocks - 1; 751 ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask); 752 endStrip = endLba >> raid->stripeShift; 753 num_strips = (u_int8_t)(endStrip - start_strip + 1); // End strip 754 if (io_info->IoforUnevenSpan) { 755 start_row = get_row_from_strip(sc, ld, start_strip, map); 756 endRow = get_row_from_strip(sc, ld, endStrip, map); 757 if (raid->spanDepth == 1) { 758 startlba_span = 0; 759 *pdBlock = start_row << raid->stripeShift; 760 } else { 761 startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row, 762 pdBlock, map, &error_code); 763 if (error_code == 1) { 764 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n", 765 __func__, __LINE__); 766 return FALSE; 767 } 768 } 769 if (startlba_span == SPAN_INVALID) { 770 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx," 771 "start strip %llx endSrip %llx\n", __func__, 772 __LINE__, (unsigned long long)start_row, 773 (unsigned long long)start_strip, 774 (unsigned long long)endStrip); 775 return FALSE; 776 } 777 io_info->start_span = startlba_span; 778 io_info->start_row = start_row; 779 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, " 780 " start strip 0x%llx endSrip 0x%llx span 0x%x\n", 781 __func__, __LINE__, (unsigned long long)start_row, 782 (unsigned long long)start_strip, 783 (unsigned long long)endStrip, startlba_span); 784 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n", 785 (unsigned long long)start_row, (unsigned long long)endRow, startlba_span); 786 } else { 787 start_row = mega_div64_32(start_strip, raid->rowDataSize); // Start Row 788 endRow = mega_div64_32(endStrip, raid->rowDataSize); 789 } 790 791 numRows = (u_int8_t)(endRow - start_row + 1); // get the row count 792 793 /* 794 * Calculate region info. (Assume region at start of first row, and 795 * assume this IO needs the full row - will adjust if not true.) 796 */ 797 regStart = start_row << raid->stripeShift; 798 regSize = stripSize; 799 800 /* Check if we can send this I/O via FastPath */ 801 if (raid->capability.fpCapable) { 802 if (isRead) 803 io_info->fpOkForIo = (raid->capability.fpReadCapable && 804 ((num_strips == 1) || 805 raid->capability. 806 fpReadAcrossStripe)); 807 else 808 io_info->fpOkForIo = (raid->capability.fpWriteCapable && 809 ((num_strips == 1) || 810 raid->capability. 811 fpWriteAcrossStripe)); 812 } 813 else 814 io_info->fpOkForIo = FALSE; 815 816 if (numRows == 1) { 817 if (num_strips == 1) { 818 /* single-strip IOs can always lock only the data needed, 819 multi-strip IOs always need to full stripe locked */ 820 regStart += ref_in_start_stripe; 821 regSize = numBlocks; 822 } 823 } 824 else if (io_info->IoforUnevenSpan == 0){ 825 // For Even span region lock optimization. 826 // If the start strip is the last in the start row 827 if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { 828 regStart += ref_in_start_stripe; 829 // initialize count to sectors from startRef to end of strip 830 regSize = stripSize - ref_in_start_stripe; 831 } 832 // add complete rows in the middle of the transfer 833 if (numRows > 2) 834 regSize += (numRows-2) << raid->stripeShift; 835 836 // if IO ends within first strip of last row 837 if (endStrip == endRow*raid->rowDataSize) 838 regSize += ref_in_end_stripe+1; 839 else 840 regSize += stripSize; 841 } else { 842 //For Uneven span region lock optimization. 843 // If the start strip is the last in the start row 844 if (start_strip == (get_strip_from_row(sc, ld, start_row, map) + 845 SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { 846 regStart += ref_in_start_stripe; 847 // initialize count to sectors from startRef to end of strip 848 regSize = stripSize - ref_in_start_stripe; 849 } 850 // add complete rows in the middle of the transfer 851 if (numRows > 2) 852 regSize += (numRows-2) << raid->stripeShift; 853 854 // if IO ends within first strip of last row 855 if (endStrip == get_strip_from_row(sc, ld, endRow, map)) 856 regSize += ref_in_end_stripe+1; 857 else 858 regSize += stripSize; 859 } 860 pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; 861 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) 862 pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; 863 else 864 pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; 865 pRAID_Context->VirtualDiskTgtId = raid->targetId; 866 pRAID_Context->regLockRowLBA = regStart; 867 pRAID_Context->regLockLength = regSize; 868 pRAID_Context->configSeqNum = raid->seqNum; 869 870 /* 871 * Get Phy Params only if FP capable, or else leave it to MR firmware 872 * to do the calculation. 873 */ 874 if (io_info->fpOkForIo) { 875 retval = io_info->IoforUnevenSpan ? 876 mr_spanset_get_phy_params(sc, ld, 877 start_strip, ref_in_start_stripe, io_info, 878 pRAID_Context, map) : 879 MR_GetPhyParams(sc, ld, start_strip, 880 ref_in_start_stripe, io_info, pRAID_Context, map); 881 /* If IO on an invalid Pd, then FP is not possible */ 882 if (io_info->devHandle == MR_PD_INVALID) 883 io_info->fpOkForIo = FALSE; 884 return retval; 885 } 886 else if (isRead) { 887 for (stripIdx=0; stripIdx<num_strips; stripIdx++) { 888 retval = io_info->IoforUnevenSpan ? 889 mr_spanset_get_phy_params(sc, ld, 890 start_strip + stripIdx, 891 ref_in_start_stripe, io_info, 892 pRAID_Context, map) : 893 MR_GetPhyParams(sc, ld, 894 start_strip + stripIdx, ref_in_start_stripe, 895 io_info, pRAID_Context, map); 896 if (!retval) 897 return TRUE; 898 } 899 } 900 #if SPAN_DEBUG 901 // Just for testing what arm we get for strip. 902 get_arm_from_strip(sc, ld, start_strip, map); 903 #endif 904 return TRUE; 905 } 906 907 /* 908 ****************************************************************************** 909 * 910 * This routine pepare spanset info from Valid Raid map and store it into 911 * local copy of ldSpanInfo per instance data structure. 912 * 913 * Inputs : 914 * map - LD map 915 * ldSpanInfo - ldSpanInfo per HBA instance 916 * 917 */ 918 void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo) 919 { 920 u_int8_t span,count; 921 u_int32_t element,span_row_width; 922 u_int64_t span_row; 923 MR_LD_RAID *raid; 924 LD_SPAN_SET *span_set, *span_set_prev; 925 MR_QUAD_ELEMENT *quad; 926 int ldCount; 927 u_int16_t ld; 928 929 if (!ldSpanInfo) 930 return; 931 932 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) 933 { 934 ld = MR_TargetIdToLdGet(ldCount, map); 935 if (ld >= MAX_LOGICAL_DRIVES) 936 continue; 937 raid = MR_LdRaidGet(ld, map); 938 for (element=0; element < MAX_QUAD_DEPTH; element++) { 939 for (span=0; span < raid->spanDepth; span++) { 940 if (map->raidMap.ldSpanMap[ld].spanBlock[span]. 941 block_span_info.noElements < element+1) 942 continue; 943 // TO-DO 944 span_set = &(ldSpanInfo[ld].span_set[element]); 945 quad = &map->raidMap.ldSpanMap[ld]. 946 spanBlock[span].block_span_info. 947 quad[element]; 948 949 span_set->diff = quad->diff; 950 951 for (count=0,span_row_width=0; 952 count<raid->spanDepth; count++) { 953 if (map->raidMap.ldSpanMap[ld]. 954 spanBlock[count]. 955 block_span_info. 956 noElements >=element+1) { 957 span_set->strip_offset[count] = 958 span_row_width; 959 span_row_width += 960 MR_LdSpanPtrGet 961 (ld, count, map)->spanRowDataSize; 962 #if SPAN_DEBUG 963 printf("LSI Debug span %x rowDataSize %x\n", 964 count, MR_LdSpanPtrGet 965 (ld, count, map)->spanRowDataSize); 966 #endif 967 } 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), quad->diff); 973 974 if (element == 0) { 975 span_set->log_start_lba = 0; 976 span_set->log_end_lba = 977 ((span_row << raid->stripeShift) * span_row_width) - 1; 978 979 span_set->span_row_start = 0; 980 span_set->span_row_end = span_row - 1; 981 982 span_set->data_strip_start = 0; 983 span_set->data_strip_end = 984 (span_row * span_row_width) - 1; 985 986 span_set->data_row_start = 0; 987 span_set->data_row_end = 988 (span_row * quad->diff) - 1; 989 } else { 990 span_set_prev = &(ldSpanInfo[ld]. 991 span_set[element - 1]); 992 span_set->log_start_lba = 993 span_set_prev->log_end_lba + 1; 994 span_set->log_end_lba = 995 span_set->log_start_lba + 996 ((span_row << raid->stripeShift) * span_row_width) - 1; 997 998 span_set->span_row_start = 999 span_set_prev->span_row_end + 1; 1000 span_set->span_row_end = 1001 span_set->span_row_start + span_row - 1; 1002 1003 span_set->data_strip_start = 1004 span_set_prev->data_strip_end + 1; 1005 span_set->data_strip_end = 1006 span_set->data_strip_start + 1007 (span_row * span_row_width) - 1; 1008 1009 span_set->data_row_start = 1010 span_set_prev->data_row_end + 1; 1011 span_set->data_row_end = 1012 span_set->data_row_start + 1013 (span_row * quad->diff) - 1; 1014 } 1015 break; 1016 } 1017 if (span == raid->spanDepth) break; // no quads remain 1018 } 1019 } 1020 #if SPAN_DEBUG 1021 getSpanInfo(map, ldSpanInfo); //to get span set info 1022 #endif 1023 } 1024 1025 /** 1026 * mrsas_update_load_balance_params: Update load balance parmas 1027 * Inputs: map pointer 1028 * Load balance info 1029 * io_info pointer 1030 * 1031 * This function updates the load balance parameters for the LD config 1032 * of a two drive optimal RAID-1. 1033 */ 1034 void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, 1035 PLD_LOAD_BALANCE_INFO lbInfo) 1036 { 1037 int ldCount; 1038 u_int16_t ld; 1039 u_int32_t pd, arRef; 1040 MR_LD_RAID *raid; 1041 1042 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) 1043 { 1044 ld = MR_TargetIdToLdGet(ldCount, map); 1045 if (ld >= MAX_LOGICAL_DRIVES) { 1046 lbInfo[ldCount].loadBalanceFlag = 0; 1047 continue; 1048 } 1049 1050 raid = MR_LdRaidGet(ld, map); 1051 1052 /* Two drive Optimal RAID 1 */ 1053 if ((raid->level == 1) && (raid->rowSize == 2) && 1054 (raid->spanDepth == 1) 1055 && raid->ldState == MR_LD_STATE_OPTIMAL) { 1056 lbInfo[ldCount].loadBalanceFlag = 1; 1057 1058 /* Get the array on which this span is present */ 1059 arRef = MR_LdSpanArrayGet(ld, 0, map); 1060 1061 /* Get the PD */ 1062 pd = MR_ArPdGet(arRef, 0, map); 1063 /* Get dev handle from PD */ 1064 lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map); 1065 pd = MR_ArPdGet(arRef, 1, map); 1066 lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map); 1067 } 1068 else 1069 lbInfo[ldCount].loadBalanceFlag = 0; 1070 } 1071 } 1072 1073 1074 /** 1075 * mrsas_set_pd_lba: Sets PD LBA 1076 * input: io_request pointer 1077 * CDB length 1078 * io_info pointer 1079 * Pointer to CCB 1080 * Local RAID map pointer 1081 * Start block of IO 1082 * Block Size 1083 * 1084 * Used to set the PD logical block address in CDB for FP IOs. 1085 */ 1086 void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len, 1087 struct IO_REQUEST_INFO *io_info, union ccb *ccb, 1088 MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, 1089 u_int32_t ld_block_size) 1090 { 1091 MR_LD_RAID *raid; 1092 u_int32_t ld; 1093 u_int64_t start_blk = io_info->pdBlock; 1094 u_int8_t *cdb = io_request->CDB.CDB32; 1095 u_int32_t num_blocks = io_info->numBlocks; 1096 u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0; 1097 struct ccb_hdr *ccb_h = &(ccb->ccb_h); 1098 1099 /* Check if T10 PI (DIF) is enabled for this LD */ 1100 ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr); 1101 raid = MR_LdRaidGet(ld, local_map_ptr); 1102 if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { 1103 memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 1104 cdb[0] = MRSAS_SCSI_VARIABLE_LENGTH_CMD; 1105 cdb[7] = MRSAS_SCSI_ADDL_CDB_LEN; 1106 1107 if (ccb_h->flags == CAM_DIR_OUT) 1108 cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32; 1109 else 1110 cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32; 1111 cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL; 1112 1113 /* LBA */ 1114 cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff); 1115 cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff); 1116 cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff); 1117 cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff); 1118 cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff); 1119 cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff); 1120 cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff); 1121 cdb[19] = (u_int8_t)(start_blk & 0xff); 1122 1123 /* Logical block reference tag */ 1124 io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag); 1125 io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff; 1126 io_request->IoFlags = 32; /* Specify 32-byte cdb */ 1127 1128 /* Transfer length */ 1129 cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff); 1130 cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff); 1131 cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff); 1132 cdb[31] = (u_int8_t)(num_blocks & 0xff); 1133 1134 /* set SCSI IO EEDP Flags */ 1135 if (ccb_h->flags == CAM_DIR_OUT) { 1136 io_request->EEDPFlags = 1137 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 1138 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 1139 MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | 1140 MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | 1141 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; 1142 } 1143 else { 1144 io_request->EEDPFlags = 1145 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 1146 MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; 1147 } 1148 io_request->Control |= (0x4 << 26); 1149 io_request->EEDPBlockSize = ld_block_size; 1150 } 1151 else { 1152 /* Some drives don't support 16/12 byte CDB's, convert to 10 */ 1153 if (((cdb_len == 12) || (cdb_len == 16)) && 1154 (start_blk <= 0xffffffff)) { 1155 if (cdb_len == 16) { 1156 opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10; 1157 flagvals = cdb[1]; 1158 groupnum = cdb[14]; 1159 control = cdb[15]; 1160 } 1161 else { 1162 opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10; 1163 flagvals = cdb[1]; 1164 groupnum = cdb[10]; 1165 control = cdb[11]; 1166 } 1167 1168 memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 1169 1170 cdb[0] = opcode; 1171 cdb[1] = flagvals; 1172 cdb[6] = groupnum; 1173 cdb[9] = control; 1174 1175 /* Transfer length */ 1176 cdb[8] = (u_int8_t)(num_blocks & 0xff); 1177 cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff); 1178 1179 io_request->IoFlags = 10; /* Specify 10-byte cdb */ 1180 cdb_len = 10; 1181 } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) { 1182 /* Convert to 16 byte CDB for large LBA's */ 1183 switch (cdb_len) { 1184 case 6: 1185 opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16; 1186 control = cdb[5]; 1187 break; 1188 case 10: 1189 opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16; 1190 flagvals = cdb[1]; 1191 groupnum = cdb[6]; 1192 control = cdb[9]; 1193 break; 1194 case 12: 1195 opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16; 1196 flagvals = cdb[1]; 1197 groupnum = cdb[10]; 1198 control = cdb[11]; 1199 break; 1200 } 1201 1202 memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 1203 1204 cdb[0] = opcode; 1205 cdb[1] = flagvals; 1206 cdb[14] = groupnum; 1207 cdb[15] = control; 1208 1209 /* Transfer length */ 1210 cdb[13] = (u_int8_t)(num_blocks & 0xff); 1211 cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff); 1212 cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff); 1213 cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff); 1214 1215 io_request->IoFlags = 16; /* Specify 16-byte cdb */ 1216 cdb_len = 16; 1217 } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) { 1218 /* convert to 10 byte CDB */ 1219 opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10; 1220 control = cdb[5]; 1221 1222 memset(cdb, 0, sizeof(io_request->CDB.CDB32)); 1223 cdb[0] = opcode; 1224 cdb[9] = control; 1225 1226 /* Set transfer length */ 1227 cdb[8] = (u_int8_t)(num_blocks & 0xff); 1228 cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff); 1229 1230 /* Specify 10-byte cdb */ 1231 cdb_len = 10; 1232 } 1233 1234 /* Fall through normal case, just load LBA here */ 1235 switch (cdb_len) 1236 { 1237 case 6: 1238 { 1239 u_int8_t val = cdb[1] & 0xE0; 1240 cdb[3] = (u_int8_t)(start_blk & 0xff); 1241 cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff); 1242 cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f); 1243 break; 1244 } 1245 case 10: 1246 cdb[5] = (u_int8_t)(start_blk & 0xff); 1247 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff); 1248 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff); 1249 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff); 1250 break; 1251 case 12: 1252 cdb[5] = (u_int8_t)(start_blk & 0xff); 1253 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff); 1254 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff); 1255 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff); 1256 break; 1257 case 16: 1258 cdb[9] = (u_int8_t)(start_blk & 0xff); 1259 cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff); 1260 cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff); 1261 cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff); 1262 cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff); 1263 cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff); 1264 cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff); 1265 cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff); 1266 break; 1267 } 1268 } 1269 } 1270 1271 /** 1272 * mrsas_get_best_arm Determine the best spindle arm 1273 * Inputs: Load balance info 1274 * 1275 * This function determines and returns the best arm by looking at the 1276 * parameters of the last PD access. 1277 */ 1278 u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, 1279 u_int64_t block, u_int32_t count) 1280 { 1281 u_int16_t pend0, pend1; 1282 u_int64_t diff0, diff1; 1283 u_int8_t bestArm; 1284 1285 /* get the pending cmds for the data and mirror arms */ 1286 pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]); 1287 pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]); 1288 1289 /* Determine the disk whose head is nearer to the req. block */ 1290 diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]); 1291 diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]); 1292 bestArm = (diff0 <= diff1 ? 0 : 1); 1293 1294 if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16)) 1295 bestArm ^= 1; 1296 1297 /* Update the last accessed block on the correct pd */ 1298 lbInfo->last_accessed_block[bestArm] = block + count - 1; 1299 1300 return bestArm; 1301 } 1302 1303 /** 1304 * mrsas_get_updated_dev_handle Get the update dev handle 1305 * Inputs: Load balance info 1306 * io_info pointer 1307 * 1308 * This function determines and returns the updated dev handle. 1309 */ 1310 u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, 1311 struct IO_REQUEST_INFO *io_info) 1312 { 1313 u_int8_t arm, old_arm; 1314 u_int16_t devHandle; 1315 1316 old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1; 1317 1318 /* get best new arm */ 1319 arm = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks); 1320 devHandle = lbInfo->raid1DevHandle[arm]; 1321 atomic_inc(&lbInfo->scsi_pending_cmds[arm]); 1322 1323 return devHandle; 1324 } 1325 1326 /** 1327 * MR_GetPhyParams Calculates arm, span, and block 1328 * Inputs: Adapter instance soft state 1329 * Logical drive number (LD) 1330 * Stripe number (stripRow) 1331 * Reference in stripe (stripRef) 1332 * Outputs: Span number 1333 * Absolute Block number in the physical disk 1334 * 1335 * This routine calculates the arm, span and block for the specified stripe 1336 * and reference in stripe. 1337 */ 1338 u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld, 1339 u_int64_t stripRow, 1340 u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, 1341 RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) 1342 { 1343 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 1344 u_int32_t pd, arRef; 1345 u_int8_t physArm, span; 1346 u_int64_t row; 1347 u_int8_t retval = TRUE; 1348 int error_code = 0; 1349 u_int64_t *pdBlock = &io_info->pdBlock; 1350 u_int16_t *pDevHandle = &io_info->devHandle; 1351 u_int32_t rowMod, armQ, arm, logArm; 1352 u_int8_t do_invader = 0; 1353 1354 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) 1355 do_invader = 1; 1356 1357 row = mega_div64_32(stripRow, raid->rowDataSize); 1358 1359 if (raid->level == 6) { 1360 logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row 1361 if (raid->rowSize == 0) 1362 return FALSE; 1363 rowMod = mega_mod64(row, raid->rowSize); // get logical row mod 1364 armQ = raid->rowSize-1-rowMod; // index of Q drive 1365 arm = armQ+1+logArm; // data always logically follows Q 1366 if (arm >= raid->rowSize) // handle wrap condition 1367 arm -= raid->rowSize; 1368 physArm = (u_int8_t)arm; 1369 } 1370 else { 1371 if (raid->modFactor == 0) 1372 return FALSE; 1373 physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map); 1374 } 1375 1376 if (raid->spanDepth == 1) { 1377 span = 0; 1378 *pdBlock = row << raid->stripeShift; 1379 } 1380 else { 1381 span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code); 1382 if (error_code == 1) 1383 return FALSE; 1384 } 1385 1386 /* Get the array on which this span is present */ 1387 arRef = MR_LdSpanArrayGet(ld, span, map); 1388 1389 pd = MR_ArPdGet(arRef, physArm, map); // Get the Pd. 1390 1391 if (pd != MR_PD_INVALID) 1392 *pDevHandle = MR_PdDevHandleGet(pd, map); // Get dev handle from Pd. 1393 else { 1394 *pDevHandle = MR_PD_INVALID; // set dev handle as invalid. 1395 if ((raid->level >= 5) && ((!do_invader) || (do_invader && 1396 raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) 1397 pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; 1398 else if (raid->level == 1) { 1399 pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd. 1400 if (pd != MR_PD_INVALID) 1401 *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd. 1402 } 1403 } 1404 1405 *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; 1406 pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 1407 return retval; 1408 } 1409 1410 /** 1411 * MR_GetSpanBlock Calculates span block 1412 * Inputs: LD 1413 * row 1414 * PD span block 1415 * RAID map pointer 1416 * Outputs: Span number 1417 * Error code 1418 * 1419 * This routine calculates the span from the span block info. 1420 */ 1421 u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk, 1422 MR_FW_RAID_MAP_ALL *map, int *div_error) 1423 { 1424 MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); 1425 MR_QUAD_ELEMENT *quad; 1426 MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 1427 u_int32_t span, j; 1428 u_int64_t blk, debugBlk; 1429 1430 for (span=0; span < raid->spanDepth; span++, pSpanBlock++) { 1431 for (j=0; j < pSpanBlock->block_span_info.noElements; j++) { 1432 quad = &pSpanBlock->block_span_info.quad[j]; 1433 if (quad->diff == 0) { 1434 *div_error = 1; 1435 return span; 1436 } 1437 if (quad->logStart <= row && row <= quad->logEnd && 1438 (mega_mod64(row-quad->logStart, quad->diff)) == 0) { 1439 if (span_blk != NULL) { 1440 blk = mega_div64_32((row-quad->logStart), quad->diff); 1441 debugBlk = blk; 1442 blk = (blk + quad->offsetInSpan) << raid->stripeShift; 1443 *span_blk = blk; 1444 } 1445 return span; 1446 } 1447 } 1448 } 1449 return span; 1450 } 1451 1452