ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

id_queue.cpp
Go to the documentation of this file.
00001 /*++
00002 
00003 Copyright (c) 2008-2010 Alexandr A. Telyatnikov (Alter)
00004 
00005 Module Name:
00006     id_probe.cpp
00007 
00008 Abstract:
00009     This module handles comamnd queue reordering and channel load balance
00010 
00011 Author:
00012     Alexander A. Telyatnikov (Alter)
00013 
00014 Environment:
00015     kernel mode only
00016 
00017 Notes:
00018 
00019     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 
00030 Revision History:
00031 
00032 --*/
00033 
00034 #include "stdafx.h"
00035 
00036 /*
00037     Get cost of insertion Req1 before Req2
00038  */
00039 LONGLONG
00040 NTAPI
00041 UniataGetCost(
00042     PHW_LU_EXTENSION LunExt,
00043     IN PATA_REQ AtaReq1,
00044     IN PATA_REQ AtaReq2
00045     )
00046 {
00047     BOOLEAN write1;
00048     BOOLEAN write2;
00049     UCHAR flags1;
00050     UCHAR flags2;
00051     LONGLONG cost;
00052     // can't insert Req1 before tooooo old Req2
00053     if(!AtaReq2->ttl)
00054         return REORDER_COST_TTL;
00055     // check if reorderable
00056     flags1 = AtaReq1->Flags;
00057     flags2 = AtaReq2->Flags;
00058     if(!((flags2 & flags1) & REQ_FLAG_REORDERABLE_CMD))
00059         return REORDER_COST_DENIED;
00060     // if at least one Req is WRITE, target areas
00061     // can not intersect
00062     write1 = (flags1 & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE;
00063     write2 = (flags2 & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE;
00064     cost = AtaReq1->lba+AtaReq1->bcount - AtaReq2->lba;
00065     if( write1 || write2 ) {
00066         // check for intersection
00067         if((AtaReq1->lba < AtaReq2->lba+AtaReq2->bcount) &&
00068            (AtaReq1->lba+AtaReq1->bcount > AtaReq2->lba)) {
00069             // Intersection...
00070             return REORDER_COST_INTERSECT;
00071         }
00072     }
00073     if(cost < 0) {
00074         cost *= (1-LunExt->SeekBackMCost);
00075     } else {
00076         cost *= (LunExt->SeekBackMCost-1);
00077     }
00078     if( write1 == write2 ) {
00079         return cost;
00080     }
00081     return (cost * LunExt->RwSwitchMCost) + LunExt->RwSwitchCost;
00082 } // end UniataGetCost()
00083 
00084 /*
00085     Insert command to proper place of command queue
00086     Perform reorder if necessary
00087  */
00088 VOID
00089 NTAPI
00090 UniataQueueRequest(
00091     IN PHW_CHANNEL chan,
00092     IN PSCSI_REQUEST_BLOCK Srb
00093     )
00094 {
00095     PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
00096     PATA_REQ AtaReq1;
00097     PATA_REQ AtaReq2;
00098 
00099     LONGLONG best_cost;
00100     LONGLONG new_cost;
00101     LONGLONG new_cost1;
00102     LONGLONG new_cost2;
00103     PATA_REQ BestAtaReq1;
00104 
00105     BOOLEAN use_reorder = chan->UseReorder/*EnableReorder*/;
00106 #ifdef QUEUE_STATISTICS
00107     BOOLEAN reordered = FALSE;
00108 #endif //QUEUE_STATISTICS
00109 
00110     PHW_LU_EXTENSION LunExt = chan->lun[GET_CDEV(Srb)];
00111     AtaReq->Srb = Srb;
00112 
00113 /*
00114 #ifdef _DEBUG
00115     if(!LunExt) {
00116         PrintNtConsole("q: chan = %#x, dev %#x\n", chan, GET_CDEV(Srb));
00117         int i;
00118         for(i=0; i<1000; i++) {
00119             AtapiStallExecution(5*1000);
00120         }
00121         return;
00122     }
00123 #endif //_DEBUG
00124 */
00125     // check if queue is empty
00126     if(LunExt->queue_depth) {
00127         AtaReq->ttl = (UCHAR)(max(LunExt->queue_depth, MIN_REQ_TTL));
00128 
00129         // init loop
00130         BestAtaReq1 =
00131         AtaReq2 = LunExt->last_req;
00132 
00133         if(use_reorder &&
00134            (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE)) {
00135             switch(Srb->QueueAction) {
00136             case SRB_ORDERED_QUEUE_TAG_REQUEST:
00137                 use_reorder = FALSE;
00138 #ifdef QUEUE_STATISTICS
00139                 chan->TryReorderTailCount++;
00140 #endif //QUEUE_STATISTICS
00141                 break;
00142             case SRB_HEAD_OF_QUEUE_TAG_REQUEST:
00143                 BestAtaReq1 = LunExt->first_req;
00144                 best_cost = -REORDER_COST_RESELECT;
00145 #ifdef QUEUE_STATISTICS
00146                 chan->TryReorderHeadCount++;
00147 #endif //QUEUE_STATISTICS
00148                 break;
00149             case SRB_SIMPLE_TAG_REQUEST:
00150             default:
00151                 best_cost = UniataGetCost(LunExt, BestAtaReq1, AtaReq);
00152                 use_reorder |= TRUE;
00153             }
00154         } else
00155         if(use_reorder) {
00156             best_cost = UniataGetCost(LunExt, BestAtaReq1, AtaReq);
00157         }
00158 
00159         if(use_reorder) {
00160 
00161 #ifdef QUEUE_STATISTICS
00162             chan->TryReorderCount++;
00163 #endif //QUEUE_STATISTICS
00164 
00165             // walk through command queue and find the best
00166             // place for insertion of the command
00167             while ((AtaReq1 = AtaReq2->prev_req)) {
00168                 new_cost1 = UniataGetCost(LunExt, AtaReq1, AtaReq);
00169                 new_cost2 = UniataGetCost(LunExt, AtaReq, AtaReq2);
00170 
00171 #ifdef QUEUE_STATISTICS
00172                 if(new_cost1 == REORDER_COST_INTERSECT ||
00173                    new_cost2 == REORDER_COST_INTERSECT)
00174                     chan->IntersectCount++;
00175 #endif //QUEUE_STATISTICS
00176 
00177                 if(new_cost2 > REORDER_COST_RESELECT)
00178                     break;
00179 
00180                 // for now I see nothing bad in RESELECT here
00181                 //ASSERT(new_cost1 <= REORDER_COST_RESELECT);
00182 
00183                 new_cost = UniataGetCost(LunExt, AtaReq1, AtaReq2);
00184                 new_cost = new_cost1 + new_cost2 - new_cost;
00185 
00186                 // check for Stop Reordering
00187                 if(new_cost > REORDER_COST_RESELECT*3)
00188                     break;
00189 
00190                 if(new_cost < best_cost) {
00191                     best_cost = new_cost;
00192                     BestAtaReq1 = AtaReq1;
00193 #ifdef QUEUE_STATISTICS
00194                     reordered = TRUE;
00195 #endif //QUEUE_STATISTICS
00196                 }
00197                 AtaReq2 = AtaReq1;
00198             }
00199 #ifdef QUEUE_STATISTICS
00200             if(reordered)
00201                 chan->ReorderCount++;
00202 #endif //QUEUE_STATISTICS
00203         }
00204         // Insert Req between Req2 & Req1
00205         AtaReq2 = BestAtaReq1->next_req;
00206         if(AtaReq2) {
00207             AtaReq2->prev_req = AtaReq;
00208             AtaReq->next_req = AtaReq2;
00209         } else {
00210             AtaReq->next_req = NULL;
00211             LunExt->last_req = AtaReq;
00212         }
00213 //        LunExt->last_req->next_req = AtaReq;
00214         BestAtaReq1->next_req = AtaReq;
00215 //        AtaReq->prev_req = LunExt->last_req;
00216         AtaReq->prev_req = BestAtaReq1;
00217 
00218         AtaReq1 = AtaReq;
00219         while((AtaReq1 = AtaReq1->next_req)) {
00220             //ASSERT(AtaReq1->ttl);
00221             AtaReq1->ttl--;
00222         }
00223 
00224     } else {
00225         // empty queue
00226         AtaReq->ttl = 0;
00227         AtaReq->prev_req =
00228         AtaReq->next_req = NULL;
00229         LunExt->first_req =
00230         LunExt->last_req = AtaReq;
00231     }
00232     LunExt->queue_depth++;
00233     chan->queue_depth++;
00234     chan->DeviceExtension->queue_depth++;
00235     // check if this is the 1st request in queue
00236     if(chan->queue_depth == 1) {
00237         chan->cur_req = LunExt->first_req;
00238     }
00239 
00240 #ifdef QUEUE_STATISTICS
00241     //ASSERT(LunExt->queue_depth);
00242     chan->QueueStat[min(MAX_QUEUE_STAT, LunExt->queue_depth)-1]++;
00243 #endif //QUEUE_STATISTICS
00244 /*
00245     ASSERT(chan->queue_depth ==
00246             (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth));
00247     ASSERT(!chan->queue_depth || chan->cur_req);
00248 */
00249     return;
00250 } // end UniataQueueRequest()
00251 
00252 /*
00253     Remove request from queue and get next request
00254  */
00255 VOID
00256 NTAPI
00257 UniataRemoveRequest(
00258     IN PHW_CHANNEL chan,
00259     IN PSCSI_REQUEST_BLOCK Srb
00260     )
00261 {
00262     if(!Srb)
00263         return;
00264     if(!chan)
00265         return;
00266 
00267     PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
00268     //PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension;
00269 
00270     ULONG cdev = GET_CDEV(Srb);
00271     PHW_LU_EXTENSION LunExt = chan->lun[cdev];
00272 
00273     if(!LunExt)
00274         return;
00275 
00276 /*
00277     ASSERT(chan->queue_depth ==
00278             (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth));
00279     ASSERT(!chan->queue_depth || chan->cur_req);
00280 */
00281     // check if queue for the device is empty
00282     if(!LunExt->queue_depth)
00283         return;
00284 
00285     // check if request is under processing (busy)
00286     if(!AtaReq->ReqState)
00287         return;
00288 
00289     // remove reqest from queue
00290     if(AtaReq->prev_req) {
00291         AtaReq->prev_req->next_req =
00292             AtaReq->next_req;
00293     } else {
00294         LunExt->first_req = AtaReq->next_req;
00295     }
00296     if(AtaReq->next_req) {
00297         AtaReq->next_req->prev_req =
00298             AtaReq->prev_req;
00299     } else {
00300         LunExt->last_req = AtaReq->prev_req;
00301     }
00302     LunExt->queue_depth--;
00303     chan->queue_depth--;
00304     chan->DeviceExtension->queue_depth--;
00305     // set LastWrite flag for Lun
00306     LunExt->last_write = ((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE);
00307 
00308     // get request from longest queue to balance load
00309     if(chan->lun[0]->queue_depth * (chan->lun[0]->LunSelectWaitCount+1) >
00310        chan->lun[1]->queue_depth * (chan->lun[1]->LunSelectWaitCount+1)) {
00311         cdev = 0;
00312     } else {
00313         cdev = 1;
00314     }
00315 /*    // prevent too long wait for actively used device
00316     if(chan->lun[cdev ^ 1]->queue_depth &&
00317        chan->lun[cdev ^ 1]->LunSelectWaitCount >= chan->lun[cdev]->queue_depth) {
00318         cdev = cdev ^ 1;
00319     }*/
00320     // get next request for processing
00321     chan->cur_req = chan->lun[cdev]->first_req;
00322     chan->cur_cdev = cdev;
00323     if(!chan->lun[cdev ^ 1]->queue_depth) {
00324         chan->lun[cdev ^ 1]->LunSelectWaitCount=0;
00325     } else {
00326         chan->lun[cdev ^ 1]->LunSelectWaitCount++;
00327     }
00328     chan->lun[cdev]->LunSelectWaitCount=0;
00329 
00330 //    chan->first_req->prev_req = NULL;
00331     AtaReq->ReqState = REQ_STATE_NONE;
00332 /*
00333     ASSERT(chan->queue_depth ==
00334             (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth));
00335     ASSERT(!chan->queue_depth || chan->cur_req);
00336 */
00337     return;
00338 } // end UniataRemoveRequest()
00339 
00340 /*
00341     Get currently processed request
00342     (from head of the queue)
00343  */
00344 PSCSI_REQUEST_BLOCK
00345 NTAPI
00346 UniataGetCurRequest(
00347     IN PHW_CHANNEL chan
00348     )
00349 {
00350 //    if(!chan->lun[]->queue_depth) {
00351     if(!chan || !chan->cur_req) {
00352         return NULL;
00353     }
00354 
00355     return chan->cur_req->Srb;
00356 } // end UniataGetCurRequest()
00357 
00358 /*
00359     Get next channel to be serviced
00360     (used in simplex mode only)
00361  */
00362 PHW_CHANNEL
00363 NTAPI
00364 UniataGetNextChannel(
00365     IN PHW_CHANNEL chan
00366     )
00367 {
00368     ULONG c=0, _c;
00369     PHW_DEVICE_EXTENSION deviceExtension;
00370     ULONG best_c;
00371     ULONG cost_c;
00372 
00373     deviceExtension = chan->DeviceExtension;
00374 
00375     if(!deviceExtension->simplexOnly) {
00376         return chan;
00377     }
00378     KdPrint2((PRINT_PREFIX "UniataGetNextChannel:\n"));
00379     best_c = -1;
00380     cost_c = 0;
00381     for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
00382         c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
00383         chan = &deviceExtension->chan[c];
00384         if(chan->queue_depth &&
00385            chan->queue_depth * (chan->ChannelSelectWaitCount+1) >
00386            cost_c) {
00387             best_c = c;
00388             cost_c = chan->queue_depth * (chan->ChannelSelectWaitCount+1);
00389         }
00390     }
00391     if(best_c == CHAN_NOT_SPECIFIED) {
00392         KdPrint2((PRINT_PREFIX "  empty queues\n"));
00393         return NULL;
00394     }
00395     deviceExtension->FirstChannelToCheck = c;
00396     for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
00397         chan = &deviceExtension->chan[_c];
00398         if(_c == best_c) {
00399             chan->ChannelSelectWaitCount = 0;
00400             continue;
00401         }
00402         chan->ChannelSelectWaitCount++;
00403         if(!chan->queue_depth) {
00404             chan->ChannelSelectWaitCount = 0;
00405         } else {
00406             chan->ChannelSelectWaitCount++;
00407         }
00408     }
00409     KdPrint2((PRINT_PREFIX "  select chan %d\n", best_c));
00410     return &deviceExtension->chan[best_c];
00411 } // end UniataGetNextChannel()

Generated on Sat May 26 2012 04:26:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.