#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rf_pqdegdags.c,v 1.17 2023/10/15 18:15:20 oster Exp $");
#include "rf_archs.h"
#if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0)
#include <dev/raidframe/raidframevar.h>
#include "rf_raid.h"
#include "rf_dag.h"
#include "rf_dagdegrd.h"
#include "rf_dagdegwr.h"
#include "rf_dagfuncs.h"
#include "rf_dagutils.h"
#include "rf_etimer.h"
#include "rf_acctrace.h"
#include "rf_general.h"
#include "rf_pqdegdags.h"
#include "rf_pq.h"
static void
applyPDA(RF_Raid_t * raidPtr, RF_PhysDiskAddr_t * pda, RF_PhysDiskAddr_t * ppda,
RF_PhysDiskAddr_t * qpda, const struct buf *bp);
#define INIT_DISK_NODE(node,name) \
rf_InitNode(node, rf_wait, RF_FALSE, rf_DiskReadFunc, rf_DiskReadUndoFunc, rf_GenericWakeupFunc, 2,1,4,0, dag_h, name, allocList); \
(node)->succedents[0] = unblockNode; \
(node)->succedents[1] = recoveryNode; \
(node)->antecedents[0] = blockNode; \
(node)->antType[0] = rf_control
#define DISK_NODE_PARAMS(_node_,_p_) \
(_node_).params[0].p = _p_ ; \
(_node_).params[1].p = (_p_)->bufPtr; \
(_node_).params[2].v = parityStripeID; \
(_node_).params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru)
#define DISK_NODE_PDA(node) ((node)->params[0].p)
RF_CREATE_DAG_FUNC_DECL(rf_PQ_DoubleDegRead)
{
rf_DoubleDegRead(raidPtr, asmap, dag_h, bp, flags, allocList,
"Rq", "PQ Recovery", rf_PQDoubleRecoveryFunc);
}
static void
applyPDA(RF_Raid_t *raidPtr, RF_PhysDiskAddr_t *pda, RF_PhysDiskAddr_t *ppda, RF_PhysDiskAddr_t *qpda, const struct buf *bp)
{
RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
RF_RaidAddr_t s0off = rf_StripeUnitOffset(layoutPtr, ppda->startSector);
RF_SectorCount_t s0len = ppda->numSector, len;
RF_SectorNum_t suoffset;
unsigned coeff;
char *pbuf = ppda->bufPtr;
char *qbuf = qpda->bufPtr;
char *buf;
int delta;
suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
len = pda->numSector;
if ((suoffset < s0off + s0len) && (suoffset + len > s0off)) {
buf = pda->bufPtr;
coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), pda->raidAddress);
coeff = (coeff % raidPtr->Layout.numDataCol);
if (suoffset < s0off) {
delta = s0off - suoffset;
buf += rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), delta);
suoffset = s0off;
len -= delta;
}
if (suoffset > s0off) {
delta = suoffset - s0off;
pbuf += rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), delta);
qbuf += rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), delta);
}
if ((suoffset + len) > (s0len + s0off))
len = s0len + s0off - suoffset;
rf_bxor(buf, pbuf, rf_RaidAddressToByte(raidPtr, len));
rf_IncQ((unsigned long *) qbuf, (unsigned long *) buf, rf_RaidAddressToByte(raidPtr, len), coeff);
}
}
void
rf_PQDoubleRecoveryFunc(RF_DagNode_t *node)
{
int np = node->numParams;
RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p;
RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p;
RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout);
int d, i;
unsigned coeff;
RF_RaidAddr_t sosAddr;
RF_SectorCount_t secPerSU = layoutPtr->sectorsPerStripeUnit;
int two = 0;
RF_PhysDiskAddr_t *ppda, *qpda, *pda, npda;
int numDataCol = layoutPtr->numDataCol;
RF_Etimer_t timer;
RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
RF_ETIMER_START(timer);
if (asmap->failedPDAs[1] &&
(asmap->failedPDAs[1]->numSector + asmap->failedPDAs[0]->numSector < secPerSU)) {
RF_ASSERT(0);
ppda = node->params[np - 6].p;
qpda = node->params[np - 4].p;
d = (np - 6);
two = 1;
} else {
ppda = node->params[np - 4].p;
qpda = node->params[np - 3].p;
d = (np - 4);
}
for (i = 0; i < d; i++) {
pda = node->params[i].p;
coeff = rf_RaidAddressToStripeUnitID(layoutPtr, pda->raidAddress);
coeff = (coeff % raidPtr->Layout.numDataCol);
applyPDA(raidPtr, pda, ppda, qpda, node->dagHdr->bp);
if (two)
applyPDA(raidPtr, pda, ppda, qpda, node->dagHdr->bp);
}
if (asmap->failedPDAs[1] == NULL) {
pda = asmap->failedPDAs[0];
sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress);
coeff = rf_RaidAddressToStripeUnitID(layoutPtr, pda->raidAddress);
coeff = (coeff % raidPtr->Layout.numDataCol);
for (i = 0; i < numDataCol; i++) {
npda.raidAddress = sosAddr + (i * secPerSU);
(raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.col), &(npda.startSector), 0);
if (RF_DEAD_DISK(raidPtr->Disks[npda.col].status))
if (i != coeff)
break;
}
RF_ASSERT(i < numDataCol);
RF_ASSERT(two == 0);
if (coeff < i)
rf_PQ_recover((unsigned long *) ppda->bufPtr, (unsigned long *) qpda->bufPtr, (unsigned long *) pda->bufPtr, (unsigned long *) ppda->bufPtr, rf_RaidAddressToByte(raidPtr, pda->numSector), coeff, i);
else
rf_PQ_recover((unsigned long *) ppda->bufPtr, (unsigned long *) qpda->bufPtr, (unsigned long *) ppda->bufPtr, (unsigned long *) pda->bufPtr, rf_RaidAddressToByte(raidPtr, pda->numSector), i, coeff);
} else
RF_PANIC();
RF_ETIMER_STOP(timer);
RF_ETIMER_EVAL(timer);
if (tracerec)
tracerec->q_us += RF_ETIMER_VAL_US(timer);
rf_GenericWakeupFunc(node, 0);
}
void
rf_PQWriteDoubleRecoveryFunc(RF_DagNode_t *node)
{
int np = node->numParams;
RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p;
RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p;
RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout);
int i;
RF_RaidAddr_t sosAddr;
unsigned coeff;
RF_StripeCount_t secPerSU = layoutPtr->sectorsPerStripeUnit;
RF_PhysDiskAddr_t *ppda, *qpda, *pda, npda;
int numDataCol = layoutPtr->numDataCol;
RF_Etimer_t timer;
RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
RF_ASSERT(node->numResults == 2);
RF_ASSERT(asmap->failedPDAs[1] == NULL);
RF_ETIMER_START(timer);
ppda = node->results[0];
qpda = node->results[1];
for (i = 0; i < numDataCol - 2; i++)
applyPDA(raidPtr, node->params[i].p, ppda, qpda, node->dagHdr->bp);
pda = asmap->failedPDAs[0];
sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress);
coeff = rf_RaidAddressToStripeUnitID(layoutPtr, pda->raidAddress);
coeff = (coeff % raidPtr->Layout.numDataCol);
for (i = 0; i < numDataCol; i++) {
npda.raidAddress = sosAddr + (i * secPerSU);
(raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.col), &(npda.startSector), 0);
if (RF_DEAD_DISK(raidPtr->Disks[npda.col].status))
if (i != coeff)
break;
}
RF_ASSERT(i < numDataCol);
if (coeff < i)
rf_PQ_recover((unsigned long *) ppda->bufPtr, (unsigned long *) qpda->bufPtr, (unsigned long *) ppda->bufPtr, (unsigned long *) qpda->bufPtr, rf_RaidAddressToByte(raidPtr, pda->numSector), coeff, i);
else
rf_PQ_recover((unsigned long *) ppda->bufPtr, (unsigned long *) qpda->bufPtr, (unsigned long *) qpda->bufPtr, (unsigned long *) ppda->bufPtr, rf_RaidAddressToByte(raidPtr, pda->numSector), i, coeff);
memset(qpda->bufPtr, 0, rf_RaidAddressToByte(raidPtr, qpda->numSector));
rf_IncQ((unsigned long *) qpda->bufPtr, (unsigned long *) ppda->bufPtr, rf_RaidAddressToByte(raidPtr, qpda->numSector), i);
RF_ASSERT(asmap->numStripeUnitsAccessed == 1);
rf_IncQ((unsigned long *) qpda->bufPtr, (unsigned long *) asmap->failedPDAs[0]->bufPtr, rf_RaidAddressToByte(raidPtr, qpda->numSector), coeff);
rf_bxor(asmap->failedPDAs[0]->bufPtr, ppda->bufPtr, rf_RaidAddressToByte(raidPtr, ppda->numSector));
for (i = 0; i < numDataCol - 2; i++)
applyPDA(raidPtr, node->params[i].p, ppda, qpda, node->dagHdr->bp);
RF_ETIMER_STOP(timer);
RF_ETIMER_EVAL(timer);
if (tracerec)
tracerec->q_us += RF_ETIMER_VAL_US(timer);
rf_GenericWakeupFunc(node, 0);
}
RF_CREATE_DAG_FUNC_DECL(rf_PQ_DDLargeWrite)
{
RF_PANIC();
}
RF_CREATE_DAG_FUNC_DECL(rf_PQ_200_CreateWriteDAG)
{
RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
RF_SectorCount_t sectorsPerSU = layoutPtr->sectorsPerStripeUnit;
int sum;
int nf = asmap->numDataFailed;
sum = asmap->failedPDAs[0]->numSector;
if (nf == 2)
sum += asmap->failedPDAs[1]->numSector;
if ((nf == 2) && (sum == (2 * sectorsPerSU))) {
rf_PQ_DDLargeWrite(raidPtr, asmap, dag_h, bp, flags, allocList);
return;
}
if ((nf == asmap->numStripeUnitsAccessed) || (sum >= sectorsPerSU)) {
rf_PQ_DDSimpleSmallWrite(raidPtr, asmap, dag_h, bp, flags, allocList);
return;
}
RF_PANIC();
}
RF_CREATE_DAG_FUNC_DECL(rf_PQ_DDSimpleSmallWrite)
{
rf_DoubleDegSmallWrite(raidPtr, asmap, dag_h, bp, flags, allocList, "Rq", "Wq", "PQ Recovery", rf_PQWriteDoubleRecoveryFunc);
}
#endif