static u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL * map) { MR_LD_RAID *raid = MR_LdRaidGet(ld, map); LD_SPAN_SET *span_set; PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; u_int32_t info, strip_offset, span, span_offset; u_int64_t span_set_Strip, span_set_Row; for (info = 0; info < MAX_QUAD_DEPTH; info++) { span_set = &(ldSpanInfo[ld].span_set[info]); if (span_set->span_row_data_width == 0) break; if (strip > span_set->data_strip_end) continue; span_set_Strip = strip - span_set->data_strip_start; strip_offset = mega_mod64(span_set_Strip, span_set->span_row_data_width); span_set_Row = mega_div64_32(span_set_Strip, span_set->span_row_data_width) * span_set->diff; for (span = 0, span_offset = 0; span < raid->spanDepth; span++) if (map->raidMap.ldSpanMap[ld].spanBlock[span]. block_span_info.noElements >= info + 1) { if (strip_offset >= span_set->strip_offset[span]) span_offset++; else break; } mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx " "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip, (unsigned long long)span_set_Strip, (unsigned long long)span_set_Row, (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset); mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip, (unsigned long long)span_set->data_row_start + (unsigned long long)span_set_Row + (span_offset - 1)); return (span_set->data_row_start + span_set_Row + (span_offset - 1)); } return -1LLU; }
static u_int32_t get_arm_from_strip(struct mrsas_softc *sc, u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL * map) { MR_LD_RAID *raid = MR_LdRaidGet(ld, map); LD_SPAN_SET *span_set; PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; u_int32_t info, strip_offset, span, span_offset; for (info = 0; info < MAX_QUAD_DEPTH; info++) { span_set = &(ldSpanInfo[ld].span_set[info]); if (span_set->span_row_data_width == 0) break; if (strip > span_set->data_strip_end) continue; strip_offset = (u_int32_t)mega_mod64 ((strip - span_set->data_strip_start), span_set->span_row_data_width); for (span = 0, span_offset = 0; span < raid->spanDepth; span++) if (map->raidMap.ldSpanMap[ld].spanBlock[span]. block_span_info.noElements >= info + 1) { if (strip_offset >= span_set->strip_offset[span]) span_offset = span_set->strip_offset[span]; else break; } mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: " "for ld=0x%x strip=0x%lx arm is 0x%x\n", ld, (long unsigned int)strip, (strip_offset - span_offset)); return (strip_offset - span_offset); } mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm" " for ld=%x strip=%lx\n", ld, (long unsigned int)strip); return -1; }
static u_int64_t get_strip_from_row(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row, MR_DRV_RAID_MAP_ALL * map) { MR_LD_RAID *raid = MR_LdRaidGet(ld, map); LD_SPAN_SET *span_set; MR_QUAD_ELEMENT *quad; PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; u_int32_t span, info; u_int64_t strip; for (info = 0; info < MAX_QUAD_DEPTH; info++) { span_set = &(ldSpanInfo[ld].span_set[info]); if (span_set->span_row_data_width == 0) break; if (row > span_set->data_row_end) continue; for (span = 0; span < raid->spanDepth; span++) if (map->raidMap.ldSpanMap[ld].spanBlock[span]. block_span_info.noElements >= info + 1) { quad = &map->raidMap.ldSpanMap[ld]. spanBlock[span].block_span_info.quad[info]; if (quad->logStart <= row && row <= quad->logEnd && mega_mod64((row - quad->logStart), quad->diff) == 0) { strip = mega_div64_32 (((row - span_set->data_row_start) - quad->logStart), quad->diff); strip *= span_set->span_row_data_width; strip += span_set->data_strip_start; strip += span_set->strip_offset[span]; return strip; } } } mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug - get_strip_from_row: returns invalid " "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row); return -1; }
/** * mrsas_setup_io: Set up data including Fast Path I/O * input: Adapter instance soft state * Pointer to command packet * Pointer to CCB * * This function builds the DCDB inquiry command. It returns 0 if the * command is built successfully, otherwise it returns a 1. */ int mrsas_setup_io(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, union ccb *ccb, u_int32_t device_id, MRSAS_RAID_SCSI_IO_REQUEST *io_request) { struct ccb_hdr *ccb_h = &(ccb->ccb_h); struct ccb_scsiio *csio = &(ccb->csio); struct IO_REQUEST_INFO io_info; MR_FW_RAID_MAP_ALL *map_ptr; u_int8_t fp_possible; u_int32_t start_lba_hi, start_lba_lo, ld_block_size; u_int32_t datalength = 0; start_lba_lo = 0; start_lba_hi = 0; fp_possible = 0; /* * READ_6 (0x08) or WRITE_6 (0x0A) cdb */ if (csio->cdb_len == 6) { datalength = (u_int32_t)csio->cdb_io.cdb_bytes[4]; start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[1] << 16) | ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 8) | (u_int32_t) csio->cdb_io.cdb_bytes[3]; start_lba_lo &= 0x1FFFFF; } /* * READ_10 (0x28) or WRITE_6 (0x2A) cdb */ else if (csio->cdb_len == 10) { datalength = (u_int32_t)csio->cdb_io.cdb_bytes[8] | ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 8); start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | ((u_int32_t) csio->cdb_io.cdb_bytes[5]); } /* * READ_12 (0xA8) or WRITE_12 (0xAA) cdb */ else if (csio->cdb_len == 12) { datalength = (u_int32_t)csio->cdb_io.cdb_bytes[6] << 24 | ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 16) | ((u_int32_t)csio->cdb_io.cdb_bytes[8] << 8) | ((u_int32_t)csio->cdb_io.cdb_bytes[9]); start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | ((u_int32_t) csio->cdb_io.cdb_bytes[5]); } /* * READ_16 (0x88) or WRITE_16 (0xx8A) cdb */ else if (csio->cdb_len == 16) { datalength = (u_int32_t)csio->cdb_io.cdb_bytes[10] << 24 | ((u_int32_t)csio->cdb_io.cdb_bytes[11] << 16) | ((u_int32_t)csio->cdb_io.cdb_bytes[12] << 8) | ((u_int32_t)csio->cdb_io.cdb_bytes[13]); start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[6] << 24) | ((u_int32_t) csio->cdb_io.cdb_bytes[7] << 16) | (u_int32_t) csio->cdb_io.cdb_bytes[8] << 8 | ((u_int32_t) csio->cdb_io.cdb_bytes[9]); start_lba_hi = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | ((u_int32_t) csio->cdb_io.cdb_bytes[5]); } memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); io_info.ldStartBlock = ((u_int64_t)start_lba_hi << 32) | start_lba_lo; io_info.numBlocks = datalength; io_info.ldTgtId = device_id; switch (ccb_h->flags & CAM_DIR_MASK) { case CAM_DIR_IN: io_info.isRead = 1; break; case CAM_DIR_OUT: io_info.isRead = 0; break; case CAM_DIR_NONE: default: mrsas_dprint(sc, MRSAS_TRACE, "From %s : DMA Flag is %d \n", __func__, ccb_h->flags & CAM_DIR_MASK); break; } map_ptr = sc->raidmap_mem[(sc->map_id & 1)]; ld_block_size = MR_LdBlockSizeGet(device_id, map_ptr, sc); if ((MR_TargetIdToLdGet(device_id, map_ptr) >= MAX_LOGICAL_DRIVES) || (!sc->fast_path_io)) { io_request->RaidContext.regLockFlags = 0; fp_possible = 0; } else { if (MR_BuildRaidContext(sc, &io_info, &io_request->RaidContext, map_ptr)) fp_possible = io_info.fpOkForIo; } if (fp_possible) { mrsas_set_pd_lba(io_request, csio->cdb_len, &io_info, ccb, map_ptr, start_lba_lo, ld_block_size); io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); io_request->RaidContext.Type = MPI2_TYPE_CUDA; io_request->RaidContext.nseg = 0x1; io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); } if ((sc->load_balance_info[device_id].loadBalanceFlag) && (io_info.isRead)) { io_info.devHandle = mrsas_get_updated_dev_handle(&sc->load_balance_info[device_id], &io_info); cmd->load_balance = MRSAS_LOAD_BALANCE_FLAG; } else cmd->load_balance = 0; cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; io_request->DevHandle = io_info.devHandle; } else { /* Not FP IO */ io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec; cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_LD_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); io_request->RaidContext.Type = MPI2_TYPE_CUDA; io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); io_request->RaidContext.nseg = 0x1; } io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = device_id; } return(0); }
/* * MR_BuildRaidContext: Set up Fast path RAID context * * This function will initiate command processing. The start/end row and strip * information is calculated then the lock is acquired. This function will * return 0 if region lock was acquired OR return num strips. */ u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info, RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map) { MR_LD_RAID *raid; u_int32_t ld, stripSize, stripe_mask; u_int64_t endLba, endStrip, endRow, start_row, start_strip; REGION_KEY regStart; REGION_LEN regSize; u_int8_t num_strips, numRows; u_int16_t ref_in_start_stripe, ref_in_end_stripe; u_int64_t ldStartBlock; u_int32_t numBlocks, ldTgtId; u_int8_t isRead, stripIdx; u_int8_t retval = 0; u_int8_t startlba_span = SPAN_INVALID; u_int64_t *pdBlock = &io_info->pdBlock; int error_code = 0; ldStartBlock = io_info->ldStartBlock; numBlocks = io_info->numBlocks; ldTgtId = io_info->ldTgtId; isRead = io_info->isRead; io_info->IoforUnevenSpan = 0; io_info->start_span = SPAN_INVALID; ld = MR_TargetIdToLdGet(ldTgtId, map); raid = MR_LdRaidGet(ld, map); if (raid->rowDataSize == 0) { if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0) return FALSE; else if (sc->UnevenSpanSupport) { io_info->IoforUnevenSpan = 1; } else { mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x," " but there is _NO_ UnevenSpanSupport\n", MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); return FALSE; } } stripSize = 1 << raid->stripeShift; stripe_mask = stripSize - 1; /* * calculate starting row and stripe, and number of strips and rows */ start_strip = ldStartBlock >> raid->stripeShift; ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask); endLba = ldStartBlock + numBlocks - 1; ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask); endStrip = endLba >> raid->stripeShift; num_strips = (u_int8_t)(endStrip - start_strip + 1); /* End strip */ if (io_info->IoforUnevenSpan) { start_row = get_row_from_strip(sc, ld, start_strip, map); endRow = get_row_from_strip(sc, ld, endStrip, map); if (raid->spanDepth == 1) { startlba_span = 0; *pdBlock = start_row << raid->stripeShift; } else { startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row, pdBlock, map, &error_code); if (error_code == 1) { mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n", __func__, __LINE__); return FALSE; } } if (startlba_span == SPAN_INVALID) { mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx," "start strip %llx endSrip %llx\n", __func__, __LINE__, (unsigned long long)start_row, (unsigned long long)start_strip, (unsigned long long)endStrip); return FALSE; } io_info->start_span = startlba_span; io_info->start_row = start_row; mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, " " start strip 0x%llx endSrip 0x%llx span 0x%x\n", __func__, __LINE__, (unsigned long long)start_row, (unsigned long long)start_strip, (unsigned long long)endStrip, startlba_span); mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n", (unsigned long long)start_row, (unsigned long long)endRow, startlba_span); } else { start_row = mega_div64_32(start_strip, raid->rowDataSize); endRow = mega_div64_32(endStrip, raid->rowDataSize); } numRows = (u_int8_t)(endRow - start_row + 1); /* get the row count */ /* * Calculate region info. (Assume region at start of first row, and * assume this IO needs the full row - will adjust if not true.) */ regStart = start_row << raid->stripeShift; regSize = stripSize; /* Check if we can send this I/O via FastPath */ if (raid->capability.fpCapable) { if (isRead) io_info->fpOkForIo = (raid->capability.fpReadCapable && ((num_strips == 1) || raid->capability.fpReadAcrossStripe)); else io_info->fpOkForIo = (raid->capability.fpWriteCapable && ((num_strips == 1) || raid->capability.fpWriteAcrossStripe)); } else io_info->fpOkForIo = FALSE; if (numRows == 1) { if (num_strips == 1) { regStart += ref_in_start_stripe; regSize = numBlocks; } } else if (io_info->IoforUnevenSpan == 0) { /* * For Even span region lock optimization. If the start strip * is the last in the start row */ if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { regStart += ref_in_start_stripe; /* * initialize count to sectors from startRef to end * of strip */ regSize = stripSize - ref_in_start_stripe; } /* add complete rows in the middle of the transfer */ if (numRows > 2) regSize += (numRows - 2) << raid->stripeShift; /* if IO ends within first strip of last row */ if (endStrip == endRow * raid->rowDataSize) regSize += ref_in_end_stripe + 1; else regSize += stripSize; } else { if (start_strip == (get_strip_from_row(sc, ld, start_row, map) + SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { regStart += ref_in_start_stripe; /* * initialize count to sectors from startRef to end * of strip */ regSize = stripSize - ref_in_start_stripe; } /* add complete rows in the middle of the transfer */ if (numRows > 2) regSize += (numRows - 2) << raid->stripeShift; /* if IO ends within first strip of last row */ if (endStrip == get_strip_from_row(sc, ld, endRow, map)) regSize += ref_in_end_stripe + 1; else regSize += stripSize; } pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) pRAID_Context->regLockFlags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; else pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; pRAID_Context->VirtualDiskTgtId = raid->targetId; pRAID_Context->regLockRowLBA = regStart; pRAID_Context->regLockLength = regSize; pRAID_Context->configSeqNum = raid->seqNum; /* * Get Phy Params only if FP capable, or else leave it to MR firmware * to do the calculation. */ if (io_info->fpOkForIo) { retval = io_info->IoforUnevenSpan ? mr_spanset_get_phy_params(sc, ld, start_strip, ref_in_start_stripe, io_info, pRAID_Context, map) : MR_GetPhyParams(sc, ld, start_strip, ref_in_start_stripe, io_info, pRAID_Context, map); /* If IO on an invalid Pd, then FP is not possible */ if (io_info->devHandle == MR_PD_INVALID) io_info->fpOkForIo = FALSE; return retval; } else if (isRead) { for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { retval = io_info->IoforUnevenSpan ? mr_spanset_get_phy_params(sc, ld, start_strip + stripIdx, ref_in_start_stripe, io_info, pRAID_Context, map) : MR_GetPhyParams(sc, ld, start_strip + stripIdx, ref_in_start_stripe, io_info, pRAID_Context, map); if (!retval) return TRUE; } } #if SPAN_DEBUG /* Just for testing what arm we get for strip. */ get_arm_from_strip(sc, ld, start_strip, map); #endif return TRUE; }