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