Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenid_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
1.7.6.1
|