mrsas_fp.c revision 272735
1265555Sambrisko/*
2265555Sambrisko * Copyright (c) 2014, LSI Corp.
3265555Sambrisko * All rights reserved.
4265555Sambrisko * Author: Marian Choy
5265555Sambrisko * Support: freebsdraid@lsi.com
6265555Sambrisko *
7265555Sambrisko * Redistribution and use in source and binary forms, with or without
8265555Sambrisko * modification, are permitted provided that the following conditions
9265555Sambrisko * are met:
10265555Sambrisko *
11265555Sambrisko * 1. Redistributions of source code must retain the above copyright
12265555Sambrisko *    notice, this list of conditions and the following disclaimer.
13265555Sambrisko * 2. Redistributions in binary form must reproduce the above copyright
14265555Sambrisko *    notice, this list of conditions and the following disclaimer in
15265555Sambrisko *    the documentation and/or other materials provided with the
16265555Sambrisko *    distribution.
17265555Sambrisko * 3. Neither the name of the <ORGANIZATION> nor the names of its
18265555Sambrisko *    contributors may be used to endorse or promote products derived
19265555Sambrisko *    from this software without specific prior written permission.
20265555Sambrisko *
21265555Sambrisko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22265555Sambrisko * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23265555Sambrisko * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24265555Sambrisko * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25265555Sambrisko * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26265555Sambrisko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27265555Sambrisko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28265555Sambrisko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29265555Sambrisko * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30265555Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31265555Sambrisko * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32265555Sambrisko * POSSIBILITY OF SUCH DAMAGE.
33265555Sambrisko *
34265555Sambrisko * The views and conclusions contained in the software and documentation
35265555Sambrisko * are those of the authors and should not be interpreted as representing
36265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project.
37265555Sambrisko *
38265555Sambrisko * Send feedback to: <megaraidfbsd@lsi.com>
39265555Sambrisko * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40265555Sambrisko *    ATTN: MegaRaid FreeBSD
41265555Sambrisko *
42265555Sambrisko */
43265555Sambrisko
44265555Sambrisko#include <sys/cdefs.h>
45265555Sambrisko__FBSDID("$FreeBSD: head/sys/dev/mrsas/mrsas_fp.c 272735 2014-10-08 08:48:18Z kadesai $");
46265555Sambrisko
47265555Sambrisko#include <dev/mrsas/mrsas.h>
48265555Sambrisko
49265555Sambrisko#include <cam/cam.h>
50265555Sambrisko#include <cam/cam_ccb.h>
51265555Sambrisko#include <cam/cam_sim.h>
52265555Sambrisko#include <cam/cam_xpt_sim.h>
53265555Sambrisko#include <cam/cam_debug.h>
54265555Sambrisko#include <cam/cam_periph.h>
55265555Sambrisko#include <cam/cam_xpt_periph.h>
56265555Sambrisko
57265555Sambrisko
58265555Sambrisko/*
59265555Sambrisko * Function prototypes
60265555Sambrisko */
61265555Sambriskou_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
62265555Sambriskou_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
63265555Sambrisko       u_int64_t block, u_int32_t count);
64265555Sambriskou_int8_t MR_BuildRaidContext(struct mrsas_softc *sc,
65265555Sambrisko        struct IO_REQUEST_INFO *io_info,
66272735Skadesai        RAID_CONTEXT *pRAID_Context, MR_DRV_RAID_MAP_ALL *map);
67265555Sambriskou_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
68265555Sambrisko        u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
69265555Sambrisko        RAID_CONTEXT *pRAID_Context,
70272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
71272735Skadesaiu_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL *map);
72272735Skadesaiu_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL *map);
73272735Skadesaiu_int16_t MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map);
74265555Sambriskou_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
75265555Sambrisko        struct IO_REQUEST_INFO *io_info);
76265555Sambriskou_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77265555Sambriskou_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
78272735Skadesai        MR_DRV_RAID_MAP_ALL *map, int *div_error);
79265555Sambriskou_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
80272735Skadesaivoid mrsas_update_load_balance_params(MR_DRV_RAID_MAP_ALL *map,
81265555Sambrisko        PLD_LOAD_BALANCE_INFO lbInfo);
82265555Sambriskovoid mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request,
83265555Sambrisko        u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb,
84272735Skadesai        MR_DRV_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
85265555Sambrisko        u_int32_t ld_block_size);
86265555Sambriskostatic u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span,
87272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
88272735Skadesaistatic u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_DRV_RAID_MAP_ALL *map);
89265555Sambriskostatic u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm,
90272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
91265555Sambriskostatic MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span,
92272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
93265555Sambriskostatic u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx,
94272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
95265555Sambriskostatic MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld,
96272735Skadesai        MR_DRV_RAID_MAP_ALL *map);
97272735SkadesaiMR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map);
98272735Skadesaivoid MR_PopulateDrvRaidMap (struct mrsas_softc *sc);
99265555Sambrisko
100272735Skadesai
101265555Sambrisko/*
102265555Sambrisko * Spanset related function prototypes
103265555Sambrisko * Added for PRL11 configuration (Uneven span support)
104265555Sambrisko */
105272735Skadesaivoid mr_update_span_set(MR_DRV_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo);
106265555Sambriskostatic u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld,
107265555Sambrisko       u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
108272735Skadesai       RAID_CONTEXT *pRAID_Context, MR_DRV_RAID_MAP_ALL *map);
109265555Sambriskostatic u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld,
110272735Skadesai       u_int64_t strip, MR_DRV_RAID_MAP_ALL *map);
111265555Sambriskostatic u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc,
112265555Sambrisko       u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
113272735Skadesai       MR_DRV_RAID_MAP_ALL *map, int *div_error);
114265555Sambriskostatic u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span,
115272735Skadesai       u_int64_t stripe, MR_DRV_RAID_MAP_ALL *map);
116265555Sambrisko
117265555Sambrisko
118265555Sambrisko/*
119265555Sambrisko * Spanset related defines
120265555Sambrisko * Added for PRL11 configuration(Uneven span support)
121265555Sambrisko */
122265555Sambrisko#define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize
123265555Sambrisko#define SPAN_ROW_DATA_SIZE(map_, ld, index_)   MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize
124265555Sambrisko#define SPAN_INVALID    0xff
125265555Sambrisko#define SPAN_DEBUG 0
126265555Sambrisko
127265555Sambrisko/*
128265555Sambrisko * Related Defines
129265555Sambrisko */
130265555Sambrisko
131265555Sambriskotypedef u_int64_t  REGION_KEY;
132265555Sambriskotypedef u_int32_t  REGION_LEN;
133265555Sambrisko
134265555Sambrisko#define MR_LD_STATE_OPTIMAL 3
135265555Sambrisko#define FALSE 0
136265555Sambrisko#define TRUE 1
137265555Sambrisko
138265555Sambrisko
139265555Sambrisko/*
140265555Sambrisko * Related Macros
141265555Sambrisko */
142265555Sambrisko
143265555Sambrisko#define ABS_DIFF(a,b)   ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) )
144265555Sambrisko
145265555Sambrisko#define swap32(x) \
146265555Sambrisko  ((unsigned int)( \
147265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
148265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
149265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
150265555Sambrisko    (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
151265555Sambrisko
152265555Sambrisko
153265555Sambrisko/*
154265555Sambrisko * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor.
155265555Sambrisko * Assumes a check for a divisor of zero is not possible.
156265555Sambrisko *
157265555Sambrisko * @param dividend   : Dividend
158265555Sambrisko * @param divisor    : Divisor
159265555Sambrisko * @return remainder
160265555Sambrisko */
161265555Sambrisko
162265555Sambrisko#define mega_mod64(dividend, divisor) ({ \
163265555Sambriskoint remainder; \
164265555Sambriskoremainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
165265555Sambriskoremainder;})
166265555Sambrisko
167265555Sambrisko#define mega_div64_32(dividend, divisor) ({ \
168265555Sambriskoint quotient; \
169265555Sambriskoquotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
170265555Sambriskoquotient;})
171265555Sambrisko
172265555Sambrisko
173265555Sambrisko/*
174265555Sambrisko * Various RAID map access functions.  These functions access the various
175265555Sambrisko * parts of the RAID map and returns the appropriate parameters.
176265555Sambrisko */
177265555Sambrisko
178272735SkadesaiMR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map)
179265555Sambrisko{
180265555Sambrisko    return (&map->raidMap.ldSpanMap[ld].ldRaid);
181265555Sambrisko}
182265555Sambrisko
183272735Skadesaiu_int16_t MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map)
184265555Sambrisko{
185265555Sambrisko    return (map->raidMap.ldSpanMap[ld].ldRaid.targetId);
186265555Sambrisko}
187265555Sambrisko
188272735Skadesaistatic u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_DRV_RAID_MAP_ALL *map)
189265555Sambrisko{
190265555Sambrisko    return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
191265555Sambrisko}
192265555Sambrisko
193272735Skadesaistatic u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_DRV_RAID_MAP_ALL *map)
194265555Sambrisko{
195265555Sambrisko    return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
196265555Sambrisko}
197265555Sambrisko
198272735Skadesaistatic u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_DRV_RAID_MAP_ALL *map)
199265555Sambrisko{
200265555Sambrisko    return map->raidMap.devHndlInfo[pd].curDevHdl;
201265555Sambrisko}
202265555Sambrisko
203272735Skadesaistatic u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_DRV_RAID_MAP_ALL *map)
204265555Sambrisko{
205265555Sambrisko    return map->raidMap.arMapInfo[ar].pd[arm];
206265555Sambrisko}
207265555Sambrisko
208272735Skadesaistatic MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_DRV_RAID_MAP_ALL *map)
209265555Sambrisko{
210265555Sambrisko    return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
211265555Sambrisko}
212265555Sambrisko
213272735Skadesaistatic MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map)
214265555Sambrisko{
215265555Sambrisko    return &map->raidMap.ldSpanMap[ld].spanBlock[0];
216265555Sambrisko}
217265555Sambrisko
218272735Skadesaiu_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL *map)
219265555Sambrisko{
220265555Sambrisko    return map->raidMap.ldTgtIdToLd[ldTgtId];
221265555Sambrisko}
222265555Sambrisko
223272735Skadesaiu_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL *map)
224265555Sambrisko{
225265555Sambrisko    MR_LD_RAID *raid;
226265555Sambrisko    u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE;
227265555Sambrisko
228265555Sambrisko    ld = MR_TargetIdToLdGet(ldTgtId, map);
229265555Sambrisko
230265555Sambrisko    /*
231265555Sambrisko     * Check if logical drive was removed.
232265555Sambrisko     */
233265555Sambrisko    if (ld >= MAX_LOGICAL_DRIVES)
234265555Sambrisko        return ldBlockSize;
235265555Sambrisko
236265555Sambrisko    raid = MR_LdRaidGet(ld, map);
237265555Sambrisko    ldBlockSize = raid->logicalBlockLength;
238265555Sambrisko    if (!ldBlockSize)
239265555Sambrisko        ldBlockSize = MRSAS_SCSIBLOCKSIZE;
240265555Sambrisko
241265555Sambrisko    return ldBlockSize;
242265555Sambrisko}
243265555Sambrisko
244272735Skadesai/*
245272735Skadesai * This function will Populate Driver Map using firmware raid map
246272735Skadesai */
247272735Skadesaivoid MR_PopulateDrvRaidMap(struct mrsas_softc *sc)
248272735Skadesai{
249272735Skadesai	MR_FW_RAID_MAP_ALL     *fw_map_old    = NULL;
250272735Skadesai	MR_FW_RAID_MAP         *pFwRaidMap    = NULL;
251272735Skadesai	unsigned int i;
252272735Skadesai
253272735Skadesai	MR_DRV_RAID_MAP_ALL *drv_map = sc->ld_drv_map[(sc->map_id & 1)];
254272735Skadesai	MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;
255272735Skadesai
256272735Skadesai	if(sc->max256vdSupport) {
257272735Skadesai		memcpy(sc->ld_drv_map[sc->map_id & 1],
258272735Skadesai				sc->raidmap_mem[sc->map_id & 1],
259272735Skadesai				sc->current_map_sz);
260272735Skadesai		/* New Raid map will not set totalSize, so keep expected value
261272735Skadesai		 * for legacy code in ValidateMapInfo
262272735Skadesai		 */
263272735Skadesai		pDrvRaidMap->totalSize = sizeof (MR_FW_RAID_MAP_EXT);
264272735Skadesai	} else {
265272735Skadesai		fw_map_old =(MR_FW_RAID_MAP_ALL *) sc->raidmap_mem[(sc->map_id & 1)];
266272735Skadesai		pFwRaidMap = &fw_map_old->raidMap;
267272735Skadesai
268272735Skadesai#if VD_EXT_DEBUG
269272735Skadesai		for (i = 0; i < pFwRaidMap->ldCount; i++) {
270272735Skadesai			device_printf(sc->mrsas_dev,
271272735Skadesai					"Index 0x%x Target Id 0x%x Seq Num 0x%x Size 0/%lx\n", i,
272272735Skadesai					fw_map_old->raidMap.ldSpanMap[i].ldRaid.targetId,
273272735Skadesai					fw_map_old->raidMap.ldSpanMap[i].ldRaid.seqNum,
274272735Skadesai					fw_map_old->raidMap.ldSpanMap[i].ldRaid.size );
275272735Skadesai		}
276272735Skadesai#endif
277272735Skadesai
278272735Skadesai		memset(drv_map, 0, sc->drv_map_sz);
279272735Skadesai		pDrvRaidMap->totalSize = pFwRaidMap->totalSize;
280272735Skadesai		pDrvRaidMap->ldCount = pFwRaidMap->ldCount;
281272735Skadesai		pDrvRaidMap->fpPdIoTimeoutSec =
282272735Skadesai			pFwRaidMap->fpPdIoTimeoutSec;
283272735Skadesai
284272735Skadesai		for(i=0; i < MAX_RAIDMAP_LOGICAL_DRIVES+MAX_RAIDMAP_VIEWS; i++) {
285272735Skadesai			pDrvRaidMap->ldTgtIdToLd[i] =
286272735Skadesai				(u_int8_t)pFwRaidMap->ldTgtIdToLd[i];
287272735Skadesai		}
288272735Skadesai
289272735Skadesai		for(i=0; i < pDrvRaidMap->ldCount; i++) {
290272735Skadesai			pDrvRaidMap->ldSpanMap[i] =
291272735Skadesai				pFwRaidMap->ldSpanMap[i];
292272735Skadesai
293272735Skadesai#if VD_EXT_DEBUG
294272735Skadesai	        device_printf(sc->mrsas_dev, "pFwRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x "
295272735Skadesai			"pFwRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x size 0x%x\n",
296272735Skadesai			i, i, pFwRaidMap->ldSpanMap[i].ldRaid.targetId,
297272735Skadesai			pFwRaidMap->ldSpanMap[i].ldRaid.seqNum,
298272735Skadesai			(u_int32_t)pFwRaidMap->ldSpanMap[i].ldRaid.rowSize);
299272735Skadesai		device_printf(sc->mrsas_dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x"
300272735Skadesai			"pDrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x size 0x%x\n",i, i,
301272735Skadesai			pDrvRaidMap->ldSpanMap[i].ldRaid.targetId,
302272735Skadesai			pDrvRaidMap->ldSpanMap[i].ldRaid.seqNum,
303272735Skadesai			(u_int32_t)pDrvRaidMap->ldSpanMap[i].ldRaid.rowSize);
304272735Skadesai		device_printf(sc->mrsas_dev, "drv raid map all %p raid map %p LD RAID MAP %p/%p\n",
305272735Skadesai			drv_map, pDrvRaidMap,
306272735Skadesai			&pFwRaidMap->ldSpanMap[i].ldRaid, &pDrvRaidMap->ldSpanMap[i].ldRaid);
307272735Skadesai#endif
308272735Skadesai		}
309272735Skadesai
310272735Skadesai		memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo,
311272735Skadesai			sizeof(MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS);
312272735Skadesai		memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo,
313272735Skadesai			sizeof(MR_DEV_HANDLE_INFO) *
314272735Skadesai			MAX_RAIDMAP_PHYSICAL_DEVICES);
315272735Skadesai	}
316272735Skadesai}
317272735Skadesai
318265555Sambrisko/**
319265555Sambrisko * MR_ValidateMapInfo:        Validate RAID map
320265555Sambrisko * input:                     Adapter instance soft state
321265555Sambrisko *
322265555Sambrisko * This function checks and validates the loaded RAID map. It returns 0 if
323265555Sambrisko * successful, and 1 otherwise.
324265555Sambrisko */
325265555Sambriskou_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc)
326265555Sambrisko{
327265555Sambrisko	if (!sc) {
328265555Sambrisko		return 1;
329265555Sambrisko	}
330272735Skadesai
331272735Skadesai    MR_PopulateDrvRaidMap (sc);
332272735Skadesai
333272735Skadesai    MR_DRV_RAID_MAP_ALL *drv_map = sc->ld_drv_map[(sc->map_id & 1)];
334272735Skadesai    MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;
335272735Skadesai
336272735Skadesai    u_int32_t expected_map_size;
337272735Skadesai    drv_map = sc->ld_drv_map[(sc->map_id & 1)];
338272735Skadesai    pDrvRaidMap = &drv_map->raidMap;
339265555Sambrisko    PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span;
340265555Sambrisko
341272735Skadesai    if(sc->max256vdSupport)
342272735Skadesai	expected_map_size = sizeof (MR_FW_RAID_MAP_EXT);
343272735Skadesai    else
344272735Skadesai	expected_map_size =
345272735Skadesai		(sizeof (MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP)) +
346272735Skadesai		(sizeof(MR_LD_SPAN_MAP) * pDrvRaidMap->ldCount);
347265555Sambrisko
348272735Skadesai    if (pDrvRaidMap->totalSize != expected_map_size) {
349272735Skadesai        device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", expected_map_size);
350265555Sambrisko        device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP));
351272735Skadesai        device_printf(sc->mrsas_dev, "pDrvRaidMap->totalSize=%x\n", pDrvRaidMap->totalSize);
352265555Sambrisko        return 1;
353265555Sambrisko    }
354265555Sambrisko
355265555Sambrisko    if (sc->UnevenSpanSupport) {
356272735Skadesai	printf ("Updating span set\n\n");
357272735Skadesai        mr_update_span_set(drv_map, ldSpanInfo);
358265555Sambrisko	}
359265555Sambrisko
360272735Skadesai    mrsas_update_load_balance_params(drv_map, sc->load_balance_info);
361265555Sambrisko
362265555Sambrisko    return 0;
363265555Sambrisko}
364265555Sambrisko
365265555Sambrisko/*
366265555Sambrisko * ******************************************************************************
367265555Sambrisko *
368265555Sambrisko *  Function to print info about span set created in driver from FW raid map
369265555Sambrisko *
370265555Sambrisko *  Inputs :
371265555Sambrisko *  map    - LD map
372265555Sambrisko *  ldSpanInfo - ldSpanInfo per HBA instance
373265555Sambrisko *
374265555Sambrisko *
375265555Sambrisko * */
376265555Sambrisko#if SPAN_DEBUG
377272735Skadesaistatic int getSpanInfo(MR_DRV_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
378265555Sambrisko{
379265555Sambrisko
380265555Sambrisko       u_int8_t   span;
381265555Sambrisko       u_int32_t    element;
382265555Sambrisko       MR_LD_RAID *raid;
383265555Sambrisko       LD_SPAN_SET *span_set;
384265555Sambrisko       MR_QUAD_ELEMENT    *quad;
385265555Sambrisko       int ldCount;
386265555Sambrisko       u_int16_t ld;
387265555Sambrisko
388265555Sambrisko       for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
389265555Sambrisko       {
390265555Sambrisko               ld = MR_TargetIdToLdGet(ldCount, map);
391265555Sambrisko                       if (ld >= MAX_LOGICAL_DRIVES) {
392265555Sambrisko                       continue;
393265555Sambrisko               }
394265555Sambrisko               raid = MR_LdRaidGet(ld, map);
395265555Sambrisko               printf("LD %x: span_depth=%x\n", ld, raid->spanDepth);
396265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
397265555Sambrisko                       printf("Span=%x, number of quads=%x\n", span,
398265555Sambrisko                       map->raidMap.ldSpanMap[ld].spanBlock[span].
399265555Sambrisko                       block_span_info.noElements);
400265555Sambrisko               for (element=0; element < MAX_QUAD_DEPTH; element++) {
401265555Sambrisko                       span_set = &(ldSpanInfo[ld].span_set[element]);
402265555Sambrisko                       if (span_set->span_row_data_width == 0) break;
403265555Sambrisko
404265555Sambrisko                       printf("  Span Set %x: width=%x, diff=%x\n", element,
405265555Sambrisko                               (unsigned int)span_set->span_row_data_width,
406265555Sambrisko                               (unsigned int)span_set->diff);
407265555Sambrisko                       printf("    logical LBA start=0x%08lx, end=0x%08lx\n",
408265555Sambrisko                               (long unsigned int)span_set->log_start_lba,
409265555Sambrisko                               (long unsigned int)span_set->log_end_lba);
410265555Sambrisko                       printf("       span row start=0x%08lx, end=0x%08lx\n",
411265555Sambrisko                               (long unsigned int)span_set->span_row_start,
412265555Sambrisko                               (long unsigned int)span_set->span_row_end);
413265555Sambrisko                       printf("       data row start=0x%08lx, end=0x%08lx\n",
414265555Sambrisko                               (long unsigned int)span_set->data_row_start,
415265555Sambrisko                               (long unsigned int)span_set->data_row_end);
416265555Sambrisko                       printf("       data strip start=0x%08lx, end=0x%08lx\n",
417265555Sambrisko                               (long unsigned int)span_set->data_strip_start,
418265555Sambrisko                               (long unsigned int)span_set->data_strip_end);
419265555Sambrisko
420265555Sambrisko                       for (span=0; span<raid->spanDepth; span++) {
421265555Sambrisko                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
422265555Sambrisko                                       block_span_info.noElements >=element+1){
423265555Sambrisko                                       quad = &map->raidMap.ldSpanMap[ld].
424265555Sambrisko                                               spanBlock[span].block_span_info.
425265555Sambrisko                                               quad[element];
426265555Sambrisko                               printf("  Span=%x, Quad=%x, diff=%x\n", span,
427265555Sambrisko                                       element, quad->diff);
428265555Sambrisko                               printf("    offset_in_span=0x%08lx\n",
429265555Sambrisko                                       (long unsigned int)quad->offsetInSpan);
430265555Sambrisko                               printf("     logical start=0x%08lx, end=0x%08lx\n",
431265555Sambrisko                                       (long unsigned int)quad->logStart,
432265555Sambrisko                                       (long unsigned int)quad->logEnd);
433265555Sambrisko                               }
434265555Sambrisko                       }
435265555Sambrisko               }
436265555Sambrisko       }
437265555Sambrisko    return 0;
438265555Sambrisko}
439265555Sambrisko#endif
440265555Sambrisko/*
441265555Sambrisko******************************************************************************
442265555Sambrisko*
443265555Sambrisko* This routine calculates the Span block for given row using spanset.
444265555Sambrisko*
445265555Sambrisko* Inputs :
446265555Sambrisko*    instance - HBA instance
447265555Sambrisko*    ld   - Logical drive number
448265555Sambrisko*    row        - Row number
449265555Sambrisko*    map    - LD map
450265555Sambrisko*
451265555Sambrisko* Outputs :
452265555Sambrisko*
453265555Sambrisko*    span          - Span number
454265555Sambrisko*    block         - Absolute Block number in the physical disk
455265555Sambrisko*    div_error    - Devide error code.
456265555Sambrisko*/
457265555Sambrisko
458265555Sambriskou_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row,
459272735Skadesai               u_int64_t *span_blk, MR_DRV_RAID_MAP_ALL *map, int *div_error)
460265555Sambrisko{
461265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
462265555Sambrisko       LD_SPAN_SET *span_set;
463265555Sambrisko       MR_QUAD_ELEMENT    *quad;
464265555Sambrisko       u_int32_t    span, info;
465265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
466265555Sambrisko
467265555Sambrisko       for (info=0; info < MAX_QUAD_DEPTH; info++) {
468265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
469265555Sambrisko
470265555Sambrisko               if (span_set->span_row_data_width == 0) break;
471265555Sambrisko               if (row > span_set->data_row_end) continue;
472265555Sambrisko
473265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
474265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
475265555Sambrisko                               block_span_info.noElements >= info+1) {
476265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
477265555Sambrisko                                       spanBlock[span].
478265555Sambrisko                                       block_span_info.quad[info];
479265555Sambrisko                               if (quad->diff == 0) {
480265555Sambrisko                                       *div_error = 1;
481265555Sambrisko                                       return span;
482265555Sambrisko                               }
483265555Sambrisko                               if ( quad->logStart <= row  &&
484265555Sambrisko                                       row <= quad->logEnd  &&
485265555Sambrisko                                       (mega_mod64(row - quad->logStart,
486265555Sambrisko                                               quad->diff)) == 0 ) {
487265555Sambrisko                                       if (span_blk != NULL) {
488265555Sambrisko                                              u_int64_t  blk;
489265555Sambrisko                                               blk = mega_div64_32
490265555Sambrisko                                                   ((row - quad->logStart),
491265555Sambrisko                                                   quad->diff);
492265555Sambrisko                                               blk = (blk + quad->offsetInSpan)
493265555Sambrisko                                                        << raid->stripeShift;
494265555Sambrisko                                               *span_blk = blk;
495265555Sambrisko                                       }
496265555Sambrisko                                       return span;
497265555Sambrisko                               }
498265555Sambrisko                       }
499265555Sambrisko       }
500265555Sambrisko       return SPAN_INVALID;
501265555Sambrisko}
502265555Sambrisko
503265555Sambrisko/*
504265555Sambrisko******************************************************************************
505265555Sambrisko*
506265555Sambrisko* This routine calculates the row for given strip using spanset.
507265555Sambrisko*
508265555Sambrisko* Inputs :
509265555Sambrisko*    instance - HBA instance
510265555Sambrisko*    ld   - Logical drive number
511265555Sambrisko*    Strip        - Strip
512265555Sambrisko*    map    - LD map
513265555Sambrisko*
514265555Sambrisko* Outputs :
515265555Sambrisko*
516265555Sambrisko*    row         - row associated with strip
517265555Sambrisko*/
518265555Sambrisko
519265555Sambriskostatic u_int64_t  get_row_from_strip(struct mrsas_softc *sc,
520272735Skadesai       u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL *map)
521265555Sambrisko{
522265555Sambrisko       MR_LD_RAID      *raid = MR_LdRaidGet(ld, map);
523265555Sambrisko       LD_SPAN_SET     *span_set;
524265555Sambrisko       PLD_SPAN_INFO   ldSpanInfo = sc->log_to_span;
525265555Sambrisko       u_int32_t             info, strip_offset, span, span_offset;
526265555Sambrisko       u_int64_t             span_set_Strip, span_set_Row;
527265555Sambrisko
528265555Sambrisko       for (info=0; info < MAX_QUAD_DEPTH; info++) {
529265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
530265555Sambrisko
531265555Sambrisko               if (span_set->span_row_data_width == 0) break;
532265555Sambrisko               if (strip > span_set->data_strip_end) continue;
533265555Sambrisko
534265555Sambrisko               span_set_Strip = strip - span_set->data_strip_start;
535265555Sambrisko               strip_offset = mega_mod64(span_set_Strip,
536265555Sambrisko                               span_set->span_row_data_width);
537265555Sambrisko               span_set_Row = mega_div64_32(span_set_Strip,
538265555Sambrisko                               span_set->span_row_data_width) * span_set->diff;
539265555Sambrisko               for (span=0,span_offset=0; span<raid->spanDepth; span++)
540265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
541265555Sambrisko                               block_span_info.noElements >=info+1) {
542265555Sambrisko                               if (strip_offset >=
543265555Sambrisko                                       span_set->strip_offset[span])
544265555Sambrisko                                       span_offset++;
545265555Sambrisko                               else
546265555Sambrisko                                       break;
547265555Sambrisko                       }
548265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx "
549265555Sambrisko                       "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip,
550265555Sambrisko                       (unsigned long long)span_set_Strip,
551265555Sambrisko                       (unsigned long long)span_set_Row,
552265555Sambrisko                       (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset);
553265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip,
554265555Sambrisko                       (unsigned long long) span_set->data_row_start +
555265555Sambrisko                       (unsigned long long) span_set_Row + (span_offset - 1));
556265555Sambrisko               return (span_set->data_row_start + span_set_Row + (span_offset - 1));
557265555Sambrisko       }
558265555Sambrisko       return -1LLU;
559265555Sambrisko}
560265555Sambrisko
561265555Sambrisko
562265555Sambrisko/*
563265555Sambrisko******************************************************************************
564265555Sambrisko*
565265555Sambrisko* This routine calculates the Start Strip for given row using spanset.
566265555Sambrisko*
567265555Sambrisko* Inputs :
568265555Sambrisko*    instance - HBA instance
569265555Sambrisko*    ld   - Logical drive number
570265555Sambrisko*    row        - Row number
571265555Sambrisko*    map    - LD map
572265555Sambrisko*
573265555Sambrisko* Outputs :
574265555Sambrisko*
575265555Sambrisko*    Strip         - Start strip associated with row
576265555Sambrisko*/
577265555Sambrisko
578265555Sambriskostatic u_int64_t get_strip_from_row(struct mrsas_softc *sc,
579272735Skadesai               u_int32_t ld, u_int64_t row, MR_DRV_RAID_MAP_ALL *map)
580265555Sambrisko{
581265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
582265555Sambrisko       LD_SPAN_SET *span_set;
583265555Sambrisko       MR_QUAD_ELEMENT    *quad;
584265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
585265555Sambrisko       u_int32_t    span, info;
586265555Sambrisko       u_int64_t  strip;
587265555Sambrisko
588265555Sambrisko       for (info=0; info<MAX_QUAD_DEPTH; info++) {
589265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
590265555Sambrisko
591265555Sambrisko               if (span_set->span_row_data_width == 0) break;
592265555Sambrisko               if (row > span_set->data_row_end) continue;
593265555Sambrisko
594265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
595265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
596265555Sambrisko                               block_span_info.noElements >=info+1) {
597265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
598265555Sambrisko                                       spanBlock[span].block_span_info.quad[info];
599265555Sambrisko                               if ( quad->logStart <= row  &&
600265555Sambrisko                                       row <= quad->logEnd  &&
601265555Sambrisko                                       mega_mod64((row - quad->logStart),
602265555Sambrisko                                       quad->diff) == 0 ) {
603265555Sambrisko                                       strip = mega_div64_32
604265555Sambrisko                                               (((row - span_set->data_row_start)
605265555Sambrisko                                                       - quad->logStart),
606265555Sambrisko                                                       quad->diff);
607265555Sambrisko                                       strip *= span_set->span_row_data_width;
608265555Sambrisko                                       strip += span_set->data_strip_start;
609265555Sambrisko                                       strip += span_set->strip_offset[span];
610265555Sambrisko                                       return strip;
611265555Sambrisko                               }
612265555Sambrisko                       }
613265555Sambrisko       }
614265555Sambrisko       mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid "
615265555Sambrisko               "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row);
616265555Sambrisko       return -1;
617265555Sambrisko}
618265555Sambrisko
619265555Sambrisko/*
620265555Sambrisko******************************************************************************
621265555Sambrisko*
622265555Sambrisko* This routine calculates the Physical Arm for given strip using spanset.
623265555Sambrisko*
624265555Sambrisko* Inputs :
625265555Sambrisko*    instance - HBA instance
626265555Sambrisko*    ld   - Logical drive number
627265555Sambrisko*    strip      - Strip
628265555Sambrisko*    map    - LD map
629265555Sambrisko*
630265555Sambrisko* Outputs :
631265555Sambrisko*
632265555Sambrisko*    Phys Arm         - Phys Arm associated with strip
633265555Sambrisko*/
634265555Sambrisko
635265555Sambriskostatic u_int32_t get_arm_from_strip(struct mrsas_softc *sc,
636272735Skadesai       u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL *map)
637265555Sambrisko{
638265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
639265555Sambrisko       LD_SPAN_SET *span_set;
640265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
641265555Sambrisko       u_int32_t    info, strip_offset, span, span_offset;
642265555Sambrisko
643265555Sambrisko       for (info=0; info<MAX_QUAD_DEPTH; info++) {
644265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
645265555Sambrisko
646265555Sambrisko               if (span_set->span_row_data_width == 0) break;
647265555Sambrisko               if (strip > span_set->data_strip_end) continue;
648265555Sambrisko
649265555Sambrisko               strip_offset = (u_int32_t)mega_mod64
650265555Sambrisko                               ((strip - span_set->data_strip_start),
651265555Sambrisko                               span_set->span_row_data_width);
652265555Sambrisko
653265555Sambrisko               for (span=0,span_offset=0; span<raid->spanDepth; span++)
654265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
655265555Sambrisko                               block_span_info.noElements >=info+1) {
656265555Sambrisko                               if (strip_offset >=
657265555Sambrisko                                       span_set->strip_offset[span])
658265555Sambrisko                                       span_offset =
659265555Sambrisko                                               span_set->strip_offset[span];
660265555Sambrisko                               else
661265555Sambrisko                                       break;
662265555Sambrisko                       }
663265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: "
664265555Sambrisko                       " for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
665265555Sambrisko                       (long unsigned int)strip, (strip_offset - span_offset));
666265555Sambrisko               return (strip_offset - span_offset);
667265555Sambrisko       }
668265555Sambrisko
669265555Sambrisko       mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm"
670265555Sambrisko               " for ld=%x strip=%lx\n", ld, (long unsigned int)strip);
671265555Sambrisko
672265555Sambrisko       return -1;
673265555Sambrisko}
674265555Sambrisko
675265555Sambrisko
676265555Sambrisko/* This Function will return Phys arm */
677265555Sambriskou_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe,
678272735Skadesai               MR_DRV_RAID_MAP_ALL *map)
679265555Sambrisko{
680265555Sambrisko       MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
681265555Sambrisko       /* Need to check correct default value */
682265555Sambrisko       u_int32_t    arm = 0;
683265555Sambrisko
684265555Sambrisko       switch (raid->level) {
685265555Sambrisko               case 0:
686265555Sambrisko               case 5:
687265555Sambrisko               case 6:
688265555Sambrisko                       arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
689265555Sambrisko                       break;
690265555Sambrisko               case 1:
691265555Sambrisko                       // start with logical arm
692265555Sambrisko                       arm = get_arm_from_strip(sc, ld, stripe, map);
693265555Sambrisko                       arm *= 2;
694265555Sambrisko                       break;
695265555Sambrisko
696265555Sambrisko       }
697265555Sambrisko
698265555Sambrisko       return arm;
699265555Sambrisko}
700265555Sambrisko
701265555Sambrisko/*
702265555Sambrisko******************************************************************************
703265555Sambrisko*
704265555Sambrisko* This routine calculates the arm, span and block for the specified stripe and
705265555Sambrisko* reference in stripe using spanset
706265555Sambrisko*
707265555Sambrisko* Inputs :
708265555Sambrisko*
709265555Sambrisko*    ld   - Logical drive number
710265555Sambrisko*    stripRow        - Stripe number
711265555Sambrisko*    stripRef    - Reference in stripe
712265555Sambrisko*
713265555Sambrisko* Outputs :
714265555Sambrisko*
715265555Sambrisko*    span          - Span number
716265555Sambrisko*    block         - Absolute Block number in the physical disk
717265555Sambrisko*/
718265555Sambriskostatic u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow,
719265555Sambrisko                  u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
720272735Skadesai                  RAID_CONTEXT *pRAID_Context, MR_DRV_RAID_MAP_ALL *map)
721265555Sambrisko{
722265555Sambrisko       MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
723265555Sambrisko       u_int32_t     pd, arRef;
724265555Sambrisko       u_int8_t      physArm, span;
725265555Sambrisko       u_int64_t     row;
726265555Sambrisko       u_int8_t      retval = TRUE;
727265555Sambrisko       u_int64_t     *pdBlock = &io_info->pdBlock;
728265555Sambrisko       u_int16_t     *pDevHandle = &io_info->devHandle;
729265555Sambrisko       u_int32_t     logArm, rowMod, armQ, arm;
730265555Sambrisko       u_int8_t do_invader = 0;
731265555Sambrisko
732265555Sambrisko       if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
733265555Sambrisko           do_invader = 1;
734265555Sambrisko
735265555Sambrisko       // Get row and span from io_info for Uneven Span IO.
736265555Sambrisko       row         = io_info->start_row;
737265555Sambrisko       span        = io_info->start_span;
738265555Sambrisko
739265555Sambrisko
740265555Sambrisko       if (raid->level == 6) {
741265555Sambrisko               logArm = get_arm_from_strip(sc, ld, stripRow, map);
742265555Sambrisko               rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
743265555Sambrisko               armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod;
744265555Sambrisko               arm = armQ + 1 + logArm;
745265555Sambrisko               if (arm >= SPAN_ROW_SIZE(map, ld, span))
746265555Sambrisko                       arm -= SPAN_ROW_SIZE(map ,ld ,span);
747265555Sambrisko               physArm = (u_int8_t)arm;
748265555Sambrisko       } else
749265555Sambrisko               // Calculate the arm
750265555Sambrisko               physArm = get_arm(sc, ld, span, stripRow, map);
751265555Sambrisko
752265555Sambrisko
753265555Sambrisko       arRef       = MR_LdSpanArrayGet(ld, span, map);
754265555Sambrisko       pd          = MR_ArPdGet(arRef, physArm, map);
755265555Sambrisko
756265555Sambrisko       if (pd != MR_PD_INVALID)
757265555Sambrisko               *pDevHandle = MR_PdDevHandleGet(pd, map);
758265555Sambrisko       else {
759265555Sambrisko               *pDevHandle = MR_PD_INVALID;
760265555Sambrisko               if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
761265555Sambrisko                  raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
762265555Sambrisko                  pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
763265555Sambrisko               else if (raid->level == 1) {
764265555Sambrisko               	  pd = MR_ArPdGet(arRef, physArm + 1, map);
765265555Sambrisko                  if (pd != MR_PD_INVALID)
766265555Sambrisko                     *pDevHandle = MR_PdDevHandleGet(pd, map);
767265555Sambrisko               }
768265555Sambrisko       }
769265555Sambrisko
770265555Sambrisko       *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
771265555Sambrisko       pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
772265555Sambrisko       return retval;
773265555Sambrisko}
774265555Sambrisko
775265555Sambrisko/**
776265555Sambrisko* MR_BuildRaidContext:           Set up Fast path RAID context
777265555Sambrisko*
778265555Sambrisko* This function will initiate command processing.  The start/end row
779265555Sambrisko* and strip information is calculated then the lock is acquired.
780265555Sambrisko* This function will return 0 if region lock was acquired OR return
781265555Sambrisko* num strips.
782265555Sambrisko*/
783265555Sambriskou_int8_t
784265555SambriskoMR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info,
785272735Skadesai                    RAID_CONTEXT *pRAID_Context, MR_DRV_RAID_MAP_ALL *map)
786265555Sambrisko{
787265555Sambrisko    MR_LD_RAID *raid;
788265555Sambrisko    u_int32_t ld, stripSize, stripe_mask;
789265555Sambrisko    u_int64_t endLba, endStrip, endRow, start_row, start_strip;
790265555Sambrisko    REGION_KEY regStart;
791265555Sambrisko    REGION_LEN regSize;
792265555Sambrisko    u_int8_t num_strips, numRows;
793265555Sambrisko    u_int16_t ref_in_start_stripe, ref_in_end_stripe;
794265555Sambrisko    u_int64_t ldStartBlock;
795265555Sambrisko    u_int32_t numBlocks, ldTgtId;
796265555Sambrisko    u_int8_t isRead, stripIdx;
797265555Sambrisko    u_int8_t retval = 0;
798265555Sambrisko	u_int8_t startlba_span = SPAN_INVALID;
799265555Sambrisko    u_int64_t *pdBlock = &io_info->pdBlock;
800265555Sambrisko    int error_code = 0;
801265555Sambrisko
802265555Sambrisko    ldStartBlock = io_info->ldStartBlock;
803265555Sambrisko    numBlocks = io_info->numBlocks;
804265555Sambrisko    ldTgtId = io_info->ldTgtId;
805265555Sambrisko    isRead = io_info->isRead;
806265555Sambrisko
807265555Sambrisko	io_info->IoforUnevenSpan = 0;
808265555Sambrisko    io_info->start_span     = SPAN_INVALID;
809265555Sambrisko
810265555Sambrisko    ld = MR_TargetIdToLdGet(ldTgtId, map);
811265555Sambrisko    raid = MR_LdRaidGet(ld, map);
812265555Sambrisko
813265555Sambrisko    /*
814265555Sambrisko 	* if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
815265555Sambrisko    * return FALSE
816265555Sambrisko    */
817265555Sambrisko	if (raid->rowDataSize == 0) {
818265555Sambrisko	   if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
819265555Sambrisko		   return FALSE;
820265555Sambrisko	   else if (sc->UnevenSpanSupport) {
821265555Sambrisko		   io_info->IoforUnevenSpan = 1;
822265555Sambrisko	   }
823265555Sambrisko	   else {
824265555Sambrisko		   mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x,"
825265555Sambrisko				   " but there is _NO_ UnevenSpanSupport\n",
826265555Sambrisko		   MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
827265555Sambrisko		   return FALSE;
828265555Sambrisko	   }
829265555Sambrisko	}
830265555Sambrisko    stripSize = 1 << raid->stripeShift;
831265555Sambrisko    stripe_mask = stripSize-1;
832265555Sambrisko    /*
833265555Sambrisko     * calculate starting row and stripe, and number of strips and rows
834265555Sambrisko     */
835265555Sambrisko    start_strip = ldStartBlock >> raid->stripeShift;
836265555Sambrisko    ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask);
837265555Sambrisko    endLba = ldStartBlock + numBlocks - 1;
838265555Sambrisko    ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask);
839265555Sambrisko    endStrip = endLba >> raid->stripeShift;
840265555Sambrisko    num_strips = (u_int8_t)(endStrip - start_strip + 1);     // End strip
841265555Sambrisko       if (io_info->IoforUnevenSpan) {
842265555Sambrisko               start_row = get_row_from_strip(sc, ld, start_strip, map);
843265555Sambrisko               endRow    = get_row_from_strip(sc, ld, endStrip, map);
844265555Sambrisko               if (raid->spanDepth == 1) {
845265555Sambrisko                       startlba_span = 0;
846265555Sambrisko                       *pdBlock = start_row << raid->stripeShift;
847265555Sambrisko               } else {
848265555Sambrisko                       startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row,
849265555Sambrisko                                               pdBlock, map, &error_code);
850265555Sambrisko                       if (error_code == 1) {
851265555Sambrisko                               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n",
852265555Sambrisko                                       __func__, __LINE__);
853265555Sambrisko                               return FALSE;
854265555Sambrisko                       }
855265555Sambrisko               }
856265555Sambrisko               if (startlba_span == SPAN_INVALID) {
857265555Sambrisko                       mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx,"
858265555Sambrisko                               "start strip %llx endSrip %llx\n", __func__,
859265555Sambrisko                               __LINE__, (unsigned long long)start_row,
860265555Sambrisko                               (unsigned long long)start_strip,
861265555Sambrisko                               (unsigned long long)endStrip);
862265555Sambrisko                       return FALSE;
863265555Sambrisko               }
864265555Sambrisko               io_info->start_span     = startlba_span;
865265555Sambrisko               io_info->start_row      = start_row;
866265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, "
867265555Sambrisko                               " start strip 0x%llx endSrip 0x%llx span 0x%x\n",
868265555Sambrisko                                __func__, __LINE__, (unsigned long long)start_row,
869265555Sambrisko                               (unsigned long long)start_strip,
870265555Sambrisko                               (unsigned long long)endStrip, startlba_span);
871265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n",
872265555Sambrisko                       (unsigned long long)start_row, (unsigned long long)endRow, startlba_span);
873265555Sambrisko       } else {
874265555Sambrisko               start_row           =  mega_div64_32(start_strip, raid->rowDataSize);      // Start Row
875265555Sambrisko               endRow              =  mega_div64_32(endStrip, raid->rowDataSize);
876265555Sambrisko       }
877265555Sambrisko
878265555Sambrisko    numRows = (u_int8_t)(endRow - start_row + 1);   // get the row count
879265555Sambrisko
880265555Sambrisko    /*
881265555Sambrisko     * Calculate region info.  (Assume region at start of first row, and
882265555Sambrisko     * assume this IO needs the full row - will adjust if not true.)
883265555Sambrisko     */
884265555Sambrisko    regStart = start_row << raid->stripeShift;
885265555Sambrisko    regSize = stripSize;
886265555Sambrisko
887265555Sambrisko    /* Check if we can send this I/O via FastPath */
888265555Sambrisko    if (raid->capability.fpCapable) {
889265555Sambrisko        if (isRead)
890265555Sambrisko            io_info->fpOkForIo = (raid->capability.fpReadCapable &&
891265555Sambrisko                                              ((num_strips == 1) ||
892265555Sambrisko                                               raid->capability.
893265555Sambrisko                                               fpReadAcrossStripe));
894265555Sambrisko        else
895265555Sambrisko            io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
896265555Sambrisko                                              ((num_strips == 1) ||
897265555Sambrisko                                               raid->capability.
898265555Sambrisko                                               fpWriteAcrossStripe));
899265555Sambrisko    }
900265555Sambrisko    else
901265555Sambrisko        io_info->fpOkForIo = FALSE;
902265555Sambrisko
903265555Sambrisko    if (numRows == 1) {
904265555Sambrisko        if (num_strips == 1) {
905265555Sambrisko            /* single-strip IOs can always lock only the data needed,
906265555Sambrisko               multi-strip IOs always need to full stripe locked */
907265555Sambrisko            regStart += ref_in_start_stripe;
908265555Sambrisko            regSize = numBlocks;
909265555Sambrisko        }
910265555Sambrisko    }
911265555Sambrisko    else if (io_info->IoforUnevenSpan == 0){
912265555Sambrisko        // For Even span region lock optimization.
913265555Sambrisko        // If the start strip is the last in the start row
914265555Sambrisko        if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
915265555Sambrisko            regStart += ref_in_start_stripe;
916265555Sambrisko            // initialize count to sectors from startRef to end of strip
917265555Sambrisko            regSize = stripSize - ref_in_start_stripe;
918265555Sambrisko        }
919265555Sambrisko		// add complete rows in the middle of the transfer
920265555Sambrisko		if (numRows > 2)
921265555Sambrisko            regSize += (numRows-2) << raid->stripeShift;
922265555Sambrisko
923265555Sambrisko        // if IO ends within first strip of last row
924265555Sambrisko        if (endStrip == endRow*raid->rowDataSize)
925265555Sambrisko                        regSize += ref_in_end_stripe+1;
926265555Sambrisko                else
927265555Sambrisko                        regSize += stripSize;
928265555Sambrisko    } else {
929265555Sambrisko		//For Uneven span region lock optimization.
930265555Sambrisko        // If the start strip is the last in the start row
931265555Sambrisko        if (start_strip == (get_strip_from_row(sc, ld, start_row, map) +
932265555Sambrisko            	SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
933265555Sambrisko            regStart += ref_in_start_stripe;
934265555Sambrisko			// initialize count to sectors from startRef to end of strip
935265555Sambrisko			regSize = stripSize - ref_in_start_stripe;
936265555Sambrisko        }
937265555Sambrisko        // add complete rows in the middle of the transfer
938265555Sambrisko        if (numRows > 2)
939265555Sambrisko            regSize += (numRows-2) << raid->stripeShift;
940265555Sambrisko
941265555Sambrisko        // if IO ends within first strip of last row
942265555Sambrisko        if (endStrip == get_strip_from_row(sc, ld, endRow, map))
943265555Sambrisko            regSize += ref_in_end_stripe+1;
944265555Sambrisko        else
945265555Sambrisko            regSize += stripSize;
946265555Sambrisko    }
947265555Sambrisko    pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
948265555Sambrisko    if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
949265555Sambrisko                pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
950265555Sambrisko    else
951265555Sambrisko    	pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
952265555Sambrisko    pRAID_Context->VirtualDiskTgtId = raid->targetId;
953265555Sambrisko    pRAID_Context->regLockRowLBA = regStart;
954265555Sambrisko    pRAID_Context->regLockLength = regSize;
955265555Sambrisko    pRAID_Context->configSeqNum = raid->seqNum;
956265555Sambrisko
957265555Sambrisko    /*
958265555Sambrisko     * Get Phy Params only if FP capable, or else leave it to MR firmware
959265555Sambrisko     * to do the calculation.
960265555Sambrisko     */
961265555Sambrisko    if (io_info->fpOkForIo) {
962265555Sambrisko        retval = io_info->IoforUnevenSpan ?
963265555Sambrisko                               mr_spanset_get_phy_params(sc, ld,
964265555Sambrisko                                   start_strip, ref_in_start_stripe, io_info,
965265555Sambrisko                                   pRAID_Context, map) :
966265555Sambrisko                               MR_GetPhyParams(sc, ld, start_strip,
967265555Sambrisko                                   ref_in_start_stripe, io_info, pRAID_Context, map);
968265555Sambrisko        /* If IO on an invalid Pd, then FP is not possible */
969265555Sambrisko        if (io_info->devHandle == MR_PD_INVALID)
970265555Sambrisko            io_info->fpOkForIo = FALSE;
971265555Sambrisko        return retval;
972265555Sambrisko    }
973265555Sambrisko    else if (isRead) {
974265555Sambrisko        for (stripIdx=0; stripIdx<num_strips; stripIdx++) {
975265555Sambrisko             retval = io_info->IoforUnevenSpan ?
976265555Sambrisko                        mr_spanset_get_phy_params(sc, ld,
977265555Sambrisko                            start_strip + stripIdx,
978265555Sambrisko                            ref_in_start_stripe, io_info,
979265555Sambrisko                            pRAID_Context, map) :
980265555Sambrisko                        MR_GetPhyParams(sc, ld,
981265555Sambrisko                            start_strip + stripIdx, ref_in_start_stripe,
982265555Sambrisko                            io_info, pRAID_Context, map);
983265555Sambrisko              if (!retval)
984265555Sambrisko                  return TRUE;
985265555Sambrisko        }
986265555Sambrisko    }
987265555Sambrisko#if SPAN_DEBUG
988265555Sambrisko       // Just for testing what arm we get for strip.
989265555Sambrisko       get_arm_from_strip(sc, ld, start_strip, map);
990265555Sambrisko#endif
991265555Sambrisko    return TRUE;
992265555Sambrisko}
993265555Sambrisko
994265555Sambrisko/*
995265555Sambrisko******************************************************************************
996265555Sambrisko*
997265555Sambrisko* This routine pepare spanset info from Valid Raid map and store it into
998265555Sambrisko* local copy of ldSpanInfo per instance data structure.
999265555Sambrisko*
1000265555Sambrisko* Inputs :
1001265555Sambrisko*    map    - LD map
1002265555Sambrisko*    ldSpanInfo - ldSpanInfo per HBA instance
1003265555Sambrisko*
1004265555Sambrisko*/
1005272735Skadesaivoid mr_update_span_set(MR_DRV_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
1006265555Sambrisko{
1007265555Sambrisko       u_int8_t   span,count;
1008265555Sambrisko       u_int32_t    element,span_row_width;
1009265555Sambrisko       u_int64_t  span_row;
1010265555Sambrisko       MR_LD_RAID *raid;
1011265555Sambrisko       LD_SPAN_SET *span_set, *span_set_prev;
1012265555Sambrisko       MR_QUAD_ELEMENT    *quad;
1013265555Sambrisko       int ldCount;
1014265555Sambrisko       u_int16_t ld;
1015272735Skadesai
1016265555Sambrisko       for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
1017265555Sambrisko       {
1018265555Sambrisko               ld = MR_TargetIdToLdGet(ldCount, map);
1019272735Skadesai		printf ("ld = %d\n\n", ld);
1020265555Sambrisko               if (ld >= MAX_LOGICAL_DRIVES)
1021265555Sambrisko                       continue;
1022265555Sambrisko               raid = MR_LdRaidGet(ld, map);
1023265555Sambrisko               for (element=0; element < MAX_QUAD_DEPTH; element++) {
1024265555Sambrisko                       for (span=0; span < raid->spanDepth; span++) {
1025265555Sambrisko                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
1026265555Sambrisko                                       block_span_info.noElements < element+1)
1027265555Sambrisko                                       continue;
1028265555Sambrisko                               // TO-DO
1029265555Sambrisko                               span_set = &(ldSpanInfo[ld].span_set[element]);
1030265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
1031265555Sambrisko                                       spanBlock[span].block_span_info.
1032265555Sambrisko                                       quad[element];
1033265555Sambrisko
1034265555Sambrisko                               span_set->diff = quad->diff;
1035265555Sambrisko
1036265555Sambrisko                               for (count=0,span_row_width=0;
1037265555Sambrisko                                               count<raid->spanDepth; count++) {
1038265555Sambrisko                                       if (map->raidMap.ldSpanMap[ld].
1039265555Sambrisko                                               spanBlock[count].
1040265555Sambrisko                                               block_span_info.
1041265555Sambrisko                                               noElements >=element+1) {
1042265555Sambrisko                                               span_set->strip_offset[count] =
1043265555Sambrisko                                                       span_row_width;
1044265555Sambrisko                                               span_row_width +=
1045265555Sambrisko                                                       MR_LdSpanPtrGet
1046265555Sambrisko                                                       (ld, count, map)->spanRowDataSize;
1047265555Sambrisko#if SPAN_DEBUG
1048265555Sambrisko                                               printf("LSI Debug span %x rowDataSize %x\n",
1049265555Sambrisko                                               count, MR_LdSpanPtrGet
1050265555Sambrisko                                                       (ld, count, map)->spanRowDataSize);
1051265555Sambrisko#endif
1052265555Sambrisko                                       }
1053265555Sambrisko                               }
1054265555Sambrisko
1055265555Sambrisko                               span_set->span_row_data_width = span_row_width;
1056265555Sambrisko                               span_row = mega_div64_32(((quad->logEnd -
1057265555Sambrisko                                       quad->logStart) + quad->diff), quad->diff);
1058265555Sambrisko
1059265555Sambrisko                               if (element == 0) {
1060265555Sambrisko                                       span_set->log_start_lba = 0;
1061265555Sambrisko                                       span_set->log_end_lba =
1062265555Sambrisko                                       ((span_row << raid->stripeShift) * span_row_width) - 1;
1063265555Sambrisko
1064265555Sambrisko                                       span_set->span_row_start = 0;
1065265555Sambrisko                                       span_set->span_row_end = span_row - 1;
1066265555Sambrisko
1067265555Sambrisko                                       span_set->data_strip_start = 0;
1068265555Sambrisko                                       span_set->data_strip_end =
1069265555Sambrisko                                               (span_row * span_row_width) - 1;
1070265555Sambrisko
1071265555Sambrisko                                       span_set->data_row_start = 0;
1072265555Sambrisko                                       span_set->data_row_end =
1073265555Sambrisko                                               (span_row * quad->diff) - 1;
1074265555Sambrisko                               } else {
1075265555Sambrisko                                       span_set_prev = &(ldSpanInfo[ld].
1076265555Sambrisko                                                       span_set[element - 1]);
1077265555Sambrisko                                       span_set->log_start_lba =
1078265555Sambrisko                                               span_set_prev->log_end_lba + 1;
1079265555Sambrisko                                       span_set->log_end_lba =
1080265555Sambrisko                                               span_set->log_start_lba +
1081265555Sambrisko                                               ((span_row << raid->stripeShift) * span_row_width) - 1;
1082265555Sambrisko
1083265555Sambrisko                                       span_set->span_row_start =
1084265555Sambrisko                                               span_set_prev->span_row_end + 1;
1085265555Sambrisko                                       span_set->span_row_end =
1086265555Sambrisko                                               span_set->span_row_start + span_row - 1;
1087265555Sambrisko
1088265555Sambrisko                                       span_set->data_strip_start =
1089265555Sambrisko                                               span_set_prev->data_strip_end + 1;
1090265555Sambrisko                                       span_set->data_strip_end =
1091265555Sambrisko                                               span_set->data_strip_start +
1092265555Sambrisko                                               (span_row * span_row_width) - 1;
1093265555Sambrisko
1094265555Sambrisko                                       span_set->data_row_start =
1095265555Sambrisko                                               span_set_prev->data_row_end + 1;
1096265555Sambrisko                                       span_set->data_row_end =
1097265555Sambrisko                                               span_set->data_row_start +
1098265555Sambrisko                                               (span_row * quad->diff) - 1;
1099265555Sambrisko                               }
1100265555Sambrisko                               break;
1101265555Sambrisko               }
1102265555Sambrisko               if (span == raid->spanDepth) break; // no quads remain
1103265555Sambrisko           }
1104265555Sambrisko       }
1105265555Sambrisko#if SPAN_DEBUG
1106265555Sambrisko       getSpanInfo(map, ldSpanInfo);   //to get span set info
1107265555Sambrisko#endif
1108265555Sambrisko}
1109265555Sambrisko
1110265555Sambrisko/**
1111265555Sambrisko * mrsas_update_load_balance_params:  Update load balance parmas
1112265555Sambrisko * Inputs:                         map pointer
1113265555Sambrisko *                                 Load balance info
1114265555Sambrisko *                                 io_info pointer
1115265555Sambrisko *
1116265555Sambrisko * This function updates the load balance parameters for the LD config
1117265555Sambrisko * of a two drive optimal RAID-1.
1118265555Sambrisko */
1119272735Skadesaivoid mrsas_update_load_balance_params(MR_DRV_RAID_MAP_ALL *map,
1120265555Sambrisko        PLD_LOAD_BALANCE_INFO lbInfo)
1121265555Sambrisko{
1122265555Sambrisko    int ldCount;
1123265555Sambrisko    u_int16_t ld;
1124265555Sambrisko    u_int32_t pd, arRef;
1125265555Sambrisko    MR_LD_RAID *raid;
1126265555Sambrisko
1127265555Sambrisko    for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
1128265555Sambrisko    {
1129265555Sambrisko        ld = MR_TargetIdToLdGet(ldCount, map);
1130265555Sambrisko        if (ld >= MAX_LOGICAL_DRIVES) {
1131265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 0;
1132265555Sambrisko            continue;
1133265555Sambrisko        }
1134265555Sambrisko
1135265555Sambrisko        raid = MR_LdRaidGet(ld, map);
1136265555Sambrisko
1137265555Sambrisko        /* Two drive Optimal RAID 1 */
1138265555Sambrisko        if ((raid->level == 1) && (raid->rowSize == 2) &&
1139265555Sambrisko                (raid->spanDepth == 1)
1140265555Sambrisko                && raid->ldState == MR_LD_STATE_OPTIMAL) {
1141265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 1;
1142265555Sambrisko
1143265555Sambrisko            /* Get the array on which this span is present */
1144265555Sambrisko            arRef = MR_LdSpanArrayGet(ld, 0, map);
1145265555Sambrisko
1146265555Sambrisko            /* Get the PD */
1147265555Sambrisko            pd = MR_ArPdGet(arRef, 0, map);
1148265555Sambrisko            /* Get dev handle from PD */
1149265555Sambrisko            lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map);
1150265555Sambrisko            pd = MR_ArPdGet(arRef, 1, map);
1151265555Sambrisko            lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map);
1152265555Sambrisko        }
1153265555Sambrisko        else
1154265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 0;
1155265555Sambrisko    }
1156265555Sambrisko}
1157265555Sambrisko
1158265555Sambrisko
1159265555Sambrisko/**
1160265555Sambrisko * mrsas_set_pd_lba:    Sets PD LBA
1161265555Sambrisko * input:               io_request pointer
1162265555Sambrisko *                      CDB length
1163265555Sambrisko *                      io_info pointer
1164265555Sambrisko *                      Pointer to CCB
1165265555Sambrisko *                      Local RAID map pointer
1166265555Sambrisko *                      Start block of IO
1167265555Sambrisko *                      Block Size
1168265555Sambrisko *
1169265555Sambrisko * Used to set the PD logical block address in CDB for FP IOs.
1170265555Sambrisko */
1171265555Sambriskovoid mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len,
1172265555Sambrisko    struct IO_REQUEST_INFO *io_info, union ccb *ccb,
1173272735Skadesai    MR_DRV_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
1174265555Sambrisko    u_int32_t ld_block_size)
1175265555Sambrisko{
1176265555Sambrisko    MR_LD_RAID *raid;
1177265555Sambrisko    u_int32_t ld;
1178265555Sambrisko    u_int64_t start_blk = io_info->pdBlock;
1179265555Sambrisko    u_int8_t *cdb = io_request->CDB.CDB32;
1180265555Sambrisko    u_int32_t num_blocks = io_info->numBlocks;
1181265555Sambrisko    u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0;
1182265555Sambrisko    struct ccb_hdr *ccb_h = &(ccb->ccb_h);
1183265555Sambrisko
1184265555Sambrisko    /* Check if T10 PI (DIF) is enabled for this LD */
1185265555Sambrisko    ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
1186265555Sambrisko    raid = MR_LdRaidGet(ld, local_map_ptr);
1187265555Sambrisko    if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
1188265555Sambrisko        memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1189265555Sambrisko        cdb[0] =  MRSAS_SCSI_VARIABLE_LENGTH_CMD;
1190265555Sambrisko        cdb[7] =  MRSAS_SCSI_ADDL_CDB_LEN;
1191265555Sambrisko
1192265555Sambrisko        if (ccb_h->flags == CAM_DIR_OUT)
1193265555Sambrisko            cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32;
1194265555Sambrisko        else
1195265555Sambrisko            cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32;
1196265555Sambrisko        cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL;
1197265555Sambrisko
1198265555Sambrisko        /* LBA */
1199265555Sambrisko        cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff);
1200265555Sambrisko        cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff);
1201265555Sambrisko        cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff);
1202265555Sambrisko        cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff);
1203265555Sambrisko        cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff);
1204265555Sambrisko        cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff);
1205265555Sambrisko        cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff);
1206265555Sambrisko        cdb[19] = (u_int8_t)(start_blk & 0xff);
1207265555Sambrisko
1208265555Sambrisko        /* Logical block reference tag */
1209265555Sambrisko        io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag);
1210265555Sambrisko        io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
1211265555Sambrisko        io_request->IoFlags = 32; /* Specify 32-byte cdb */
1212265555Sambrisko
1213265555Sambrisko        /* Transfer length */
1214265555Sambrisko        cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff);
1215265555Sambrisko        cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff);
1216265555Sambrisko        cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff);
1217265555Sambrisko        cdb[31] = (u_int8_t)(num_blocks & 0xff);
1218265555Sambrisko
1219265555Sambrisko        /* set SCSI IO EEDP Flags */
1220265555Sambrisko        if (ccb_h->flags == CAM_DIR_OUT) {
1221265555Sambrisko            io_request->EEDPFlags =
1222265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
1223265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1224265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
1225265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
1226265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
1227265555Sambrisko        }
1228265555Sambrisko        else {
1229265555Sambrisko                io_request->EEDPFlags =
1230265555Sambrisko                     MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1231265555Sambrisko                     MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
1232265555Sambrisko        }
1233265555Sambrisko        io_request->Control |= (0x4 << 26);
1234265555Sambrisko        io_request->EEDPBlockSize = ld_block_size;
1235265555Sambrisko    }
1236265555Sambrisko    else {
1237265555Sambrisko        /* Some drives don't support 16/12 byte CDB's, convert to 10 */
1238265555Sambrisko        if (((cdb_len == 12) || (cdb_len == 16)) &&
1239265555Sambrisko                    (start_blk <= 0xffffffff)) {
1240265555Sambrisko            if (cdb_len == 16) {
1241265555Sambrisko                opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
1242265555Sambrisko                flagvals = cdb[1];
1243265555Sambrisko                groupnum = cdb[14];
1244265555Sambrisko                control = cdb[15];
1245265555Sambrisko            }
1246265555Sambrisko            else {
1247265555Sambrisko                opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
1248265555Sambrisko                flagvals = cdb[1];
1249265555Sambrisko                groupnum = cdb[10];
1250265555Sambrisko                control = cdb[11];
1251265555Sambrisko            }
1252265555Sambrisko
1253265555Sambrisko            memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1254265555Sambrisko
1255265555Sambrisko            cdb[0] = opcode;
1256265555Sambrisko            cdb[1] = flagvals;
1257265555Sambrisko            cdb[6] = groupnum;
1258265555Sambrisko            cdb[9] = control;
1259265555Sambrisko
1260265555Sambrisko            /* Transfer length */
1261265555Sambrisko            cdb[8] = (u_int8_t)(num_blocks & 0xff);
1262265555Sambrisko            cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1263265555Sambrisko
1264265555Sambrisko            io_request->IoFlags = 10; /* Specify 10-byte cdb */
1265265555Sambrisko            cdb_len = 10;
1266265555Sambrisko        } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
1267265555Sambrisko            /* Convert to 16 byte CDB for large LBA's */
1268265555Sambrisko            switch (cdb_len) {
1269265555Sambrisko                case 6:
1270265555Sambrisko                    opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
1271265555Sambrisko                    control = cdb[5];
1272265555Sambrisko                    break;
1273265555Sambrisko                case 10:
1274265555Sambrisko                    opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16;
1275265555Sambrisko                    flagvals = cdb[1];
1276265555Sambrisko                    groupnum = cdb[6];
1277265555Sambrisko                    control = cdb[9];
1278265555Sambrisko                    break;
1279265555Sambrisko                case 12:
1280265555Sambrisko                    opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16;
1281265555Sambrisko                    flagvals = cdb[1];
1282265555Sambrisko                    groupnum = cdb[10];
1283265555Sambrisko                    control = cdb[11];
1284265555Sambrisko                    break;
1285265555Sambrisko            }
1286265555Sambrisko
1287265555Sambrisko            memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1288265555Sambrisko
1289265555Sambrisko            cdb[0] = opcode;
1290265555Sambrisko            cdb[1] = flagvals;
1291265555Sambrisko            cdb[14] = groupnum;
1292265555Sambrisko            cdb[15] = control;
1293265555Sambrisko
1294265555Sambrisko            /* Transfer length */
1295265555Sambrisko            cdb[13] = (u_int8_t)(num_blocks & 0xff);
1296265555Sambrisko            cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff);
1297265555Sambrisko            cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff);
1298265555Sambrisko            cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff);
1299265555Sambrisko
1300265555Sambrisko            io_request->IoFlags = 16; /* Specify 16-byte cdb */
1301265555Sambrisko            cdb_len = 16;
1302265555Sambrisko        } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) {
1303265555Sambrisko            /* convert to 10 byte CDB */
1304265555Sambrisko	    opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10;
1305265555Sambrisko	    control = cdb[5];
1306265555Sambrisko
1307267838Sdelphij	    memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1308265555Sambrisko	    cdb[0] = opcode;
1309265555Sambrisko	    cdb[9] = control;
1310265555Sambrisko
1311265555Sambrisko	    /* Set transfer length */
1312265555Sambrisko	    cdb[8] = (u_int8_t)(num_blocks & 0xff);
1313265555Sambrisko	    cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1314265555Sambrisko
1315265555Sambrisko	    /* Specify 10-byte cdb */
1316265555Sambrisko	    cdb_len = 10;
1317265555Sambrisko	}
1318265555Sambrisko
1319265555Sambrisko        /* Fall through normal case, just load LBA here */
1320265555Sambrisko        switch (cdb_len)
1321265555Sambrisko        {
1322265555Sambrisko            case 6:
1323265555Sambrisko            {
1324265555Sambrisko                u_int8_t val = cdb[1] & 0xE0;
1325265555Sambrisko                cdb[3] = (u_int8_t)(start_blk & 0xff);
1326265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff);
1327265555Sambrisko                cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f);
1328265555Sambrisko                break;
1329265555Sambrisko            }
1330265555Sambrisko            case 10:
1331265555Sambrisko                cdb[5] = (u_int8_t)(start_blk & 0xff);
1332265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1333265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1334265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1335265555Sambrisko                break;
1336265555Sambrisko            case 12:
1337265555Sambrisko                cdb[5] = (u_int8_t)(start_blk & 0xff);
1338265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1339265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1340265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1341265555Sambrisko                break;
1342265555Sambrisko            case 16:
1343265555Sambrisko                cdb[9] = (u_int8_t)(start_blk & 0xff);
1344265555Sambrisko                cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff);
1345265555Sambrisko                cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff);
1346265555Sambrisko                cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff);
1347265555Sambrisko                cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff);
1348265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff);
1349265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff);
1350265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff);
1351265555Sambrisko                break;
1352265555Sambrisko        }
1353265555Sambrisko    }
1354265555Sambrisko}
1355265555Sambrisko
1356265555Sambrisko/**
1357265555Sambrisko * mrsas_get_best_arm         Determine the best spindle arm
1358265555Sambrisko * Inputs:                    Load balance info
1359265555Sambrisko *
1360265555Sambrisko * This function determines and returns the best arm by looking at the
1361265555Sambrisko * parameters of the last PD access.
1362265555Sambrisko */
1363265555Sambriskou_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
1364265555Sambrisko        u_int64_t block, u_int32_t count)
1365265555Sambrisko{
1366265555Sambrisko    u_int16_t     pend0, pend1;
1367265555Sambrisko    u_int64_t     diff0, diff1;
1368265555Sambrisko    u_int8_t      bestArm;
1369265555Sambrisko
1370265555Sambrisko    /* get the pending cmds for the data and mirror arms */
1371265555Sambrisko    pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
1372265555Sambrisko    pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
1373265555Sambrisko
1374265555Sambrisko    /* Determine the disk whose head is nearer to the req. block */
1375265555Sambrisko    diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1376265555Sambrisko    diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1377265555Sambrisko    bestArm = (diff0 <= diff1 ? 0 : 1);
1378265555Sambrisko
1379265555Sambrisko    if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16))
1380265555Sambrisko        bestArm ^= 1;
1381265555Sambrisko
1382265555Sambrisko    /* Update the last accessed block on the correct pd */
1383265555Sambrisko    lbInfo->last_accessed_block[bestArm] = block + count - 1;
1384265555Sambrisko
1385265555Sambrisko    return bestArm;
1386265555Sambrisko}
1387265555Sambrisko
1388265555Sambrisko/**
1389265555Sambrisko * mrsas_get_updated_dev_handle    Get the update dev handle
1390265555Sambrisko * Inputs:                         Load balance info
1391265555Sambrisko *                                 io_info pointer
1392265555Sambrisko *
1393265555Sambrisko * This function determines and returns the updated dev handle.
1394265555Sambrisko */
1395265555Sambriskou_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
1396265555Sambrisko        struct IO_REQUEST_INFO *io_info)
1397265555Sambrisko{
1398265555Sambrisko    u_int8_t arm, old_arm;
1399265555Sambrisko    u_int16_t devHandle;
1400265555Sambrisko
1401265555Sambrisko    old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1402265555Sambrisko
1403265555Sambrisko    /* get best new arm */
1404265555Sambrisko    arm  = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks);
1405265555Sambrisko    devHandle = lbInfo->raid1DevHandle[arm];
1406265555Sambrisko    atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1407265555Sambrisko
1408265555Sambrisko    return devHandle;
1409265555Sambrisko}
1410265555Sambrisko
1411265555Sambrisko/**
1412265555Sambrisko * MR_GetPhyParams     Calculates arm, span, and block
1413265555Sambrisko * Inputs:             Adapter instance soft state
1414265555Sambrisko *                     Logical drive number (LD)
1415265555Sambrisko *                     Stripe number (stripRow)
1416265555Sambrisko *                     Reference in stripe (stripRef)
1417265555Sambrisko * Outputs:            Span number
1418265555Sambrisko *                     Absolute Block number in the physical disk
1419265555Sambrisko *
1420265555Sambrisko * This routine calculates the arm, span and block for the specified stripe
1421265555Sambrisko * and reference in stripe.
1422265555Sambrisko */
1423265555Sambriskou_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
1424265555Sambrisko            u_int64_t stripRow,
1425265555Sambrisko            u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
1426272735Skadesai            RAID_CONTEXT *pRAID_Context, MR_DRV_RAID_MAP_ALL *map)
1427265555Sambrisko{
1428265555Sambrisko    MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
1429265555Sambrisko    u_int32_t pd, arRef;
1430265555Sambrisko    u_int8_t physArm, span;
1431265555Sambrisko    u_int64_t row;
1432265555Sambrisko    u_int8_t retval = TRUE;
1433265555Sambrisko    int error_code = 0;
1434265555Sambrisko	u_int64_t *pdBlock = &io_info->pdBlock;
1435265555Sambrisko    u_int16_t *pDevHandle = &io_info->devHandle;
1436265555Sambrisko    u_int32_t rowMod, armQ, arm, logArm;
1437265555Sambrisko	u_int8_t do_invader = 0;
1438265555Sambrisko
1439265555Sambrisko	if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
1440265555Sambrisko		do_invader = 1;
1441265555Sambrisko
1442265555Sambrisko    row =  mega_div64_32(stripRow, raid->rowDataSize);
1443265555Sambrisko
1444265555Sambrisko    if (raid->level == 6) {
1445265555Sambrisko        logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row
1446265555Sambrisko        if (raid->rowSize == 0)
1447265555Sambrisko            return FALSE;
1448265555Sambrisko        rowMod = mega_mod64(row, raid->rowSize);  // get logical row mod
1449265555Sambrisko        armQ = raid->rowSize-1-rowMod;  // index of Q drive
1450265555Sambrisko        arm = armQ+1+logArm;    // data always logically follows Q
1451265555Sambrisko        if (arm >= raid->rowSize)         // handle wrap condition
1452265555Sambrisko            arm -= raid->rowSize;
1453265555Sambrisko        physArm = (u_int8_t)arm;
1454265555Sambrisko    }
1455265555Sambrisko    else {
1456265555Sambrisko        if (raid->modFactor == 0)
1457265555Sambrisko            return FALSE;
1458265555Sambrisko        physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map);
1459265555Sambrisko    }
1460265555Sambrisko
1461265555Sambrisko    if (raid->spanDepth == 1) {
1462265555Sambrisko        span = 0;
1463265555Sambrisko        *pdBlock = row << raid->stripeShift;
1464265555Sambrisko    }
1465265555Sambrisko    else {
1466265555Sambrisko        span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
1467265555Sambrisko        if (error_code == 1)
1468265555Sambrisko            return FALSE;
1469265555Sambrisko    }
1470265555Sambrisko
1471265555Sambrisko    /*  Get the array on which this span is present */
1472265555Sambrisko    arRef = MR_LdSpanArrayGet(ld, span, map);
1473265555Sambrisko
1474265555Sambrisko    pd = MR_ArPdGet(arRef, physArm, map);     // Get the Pd.
1475265555Sambrisko
1476265555Sambrisko    if (pd != MR_PD_INVALID)
1477265555Sambrisko        *pDevHandle = MR_PdDevHandleGet(pd, map);  // Get dev handle from Pd.
1478265555Sambrisko    else {
1479265555Sambrisko        *pDevHandle = MR_PD_INVALID; // set dev handle as invalid.
1480265555Sambrisko        if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
1481265555Sambrisko             raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
1482265555Sambrisko             pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
1483265555Sambrisko        else if (raid->level == 1) {
1484265555Sambrisko            pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd.
1485265555Sambrisko            if (pd != MR_PD_INVALID)
1486265555Sambrisko                *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd.
1487265555Sambrisko        }
1488265555Sambrisko    }
1489265555Sambrisko
1490265555Sambrisko    *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
1491265555Sambrisko    pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
1492265555Sambrisko    return retval;
1493265555Sambrisko}
1494265555Sambrisko
1495265555Sambrisko/**
1496265555Sambrisko * MR_GetSpanBlock     Calculates span block
1497265555Sambrisko * Inputs:             LD
1498265555Sambrisko *                     row
1499265555Sambrisko *                     PD span block
1500265555Sambrisko *                     RAID map pointer
1501265555Sambrisko * Outputs:            Span number
1502265555Sambrisko *                     Error code
1503265555Sambrisko *
1504265555Sambrisko * This routine calculates the span from the span block info.
1505265555Sambrisko */
1506265555Sambriskou_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
1507272735Skadesai        MR_DRV_RAID_MAP_ALL *map, int *div_error)
1508265555Sambrisko{
1509265555Sambrisko    MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
1510265555Sambrisko    MR_QUAD_ELEMENT *quad;
1511265555Sambrisko    MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1512265555Sambrisko    u_int32_t span, j;
1513265555Sambrisko    u_int64_t blk, debugBlk;
1514265555Sambrisko
1515265555Sambrisko    for (span=0; span < raid->spanDepth; span++, pSpanBlock++) {
1516265555Sambrisko        for (j=0; j < pSpanBlock->block_span_info.noElements; j++) {
1517265555Sambrisko            quad = &pSpanBlock->block_span_info.quad[j];
1518265555Sambrisko            if (quad->diff == 0) {
1519265555Sambrisko                *div_error = 1;
1520265555Sambrisko                return span;
1521265555Sambrisko            }
1522265555Sambrisko            if (quad->logStart <= row  &&  row <= quad->logEnd  &&
1523265555Sambrisko                    (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
1524265555Sambrisko                if (span_blk != NULL) {
1525265555Sambrisko                    blk =  mega_div64_32((row-quad->logStart), quad->diff);
1526265555Sambrisko                    debugBlk = blk;
1527265555Sambrisko                    blk = (blk + quad->offsetInSpan) << raid->stripeShift;
1528265555Sambrisko                    *span_blk = blk;
1529265555Sambrisko                }
1530265555Sambrisko                return span;
1531265555Sambrisko            }
1532265555Sambrisko        }
1533265555Sambrisko    }
1534265555Sambrisko    return span;
1535265555Sambrisko}
1536265555Sambrisko
1537