Ll_re_block () function: This function applies to all kernel Block devices for read/write requests. This function first creates a request item and inserts it into the request queue of the specified block device. The actual read/write operation is to use the request item Function request_fn () -For hard disk, It is do_hd_request (). after the function creates a request item, it first checks whether the corresponding request item queue is empty. If it is empty, it sets this request item as the current request item, otherwise, the request is added to the Request queue using the elevator algorithm. After each do_hd_request () finishes processing each request item, it calls do_hd_request () again through the terminal callback function (read_intr and write_intr) to process other request items in the request item queue. If the request item queue is empty, stop sending the request when the request item is empty (implemented through the init_request macro ).
The implementation and call relationships between ll_re_block (), read_intr, and write_intr are analyzed as follows:
Void do_hd_request (void)
{
// Define some parameters used by the hard disk
Int I, R;
Unsigned int block, dev;
Unsigned int sec, Head, cyl;
Unsigned int nsect;
// A macro defined by the GOTO statement to check whether the request item queue is empty
Init_request;
// Initialize the hard disk parameters and check the parameters accordingly.
Dev = minor (current-> Dev );
Block = Current-> sector;
If (Dev> = 5 * nr_hd | block + 2> HD [Dev]. nr_sects ){
End_request (0 );
Goto repeat;
}
Block + = HD [Dev]. start_sect;
Dev/= 5;
_ ASM _ ("divl % 4": "= A" (Block), "= D" (SEC): "0" (Block ), "1" (0 ),
"R" (hd_info [Dev]. sect ));
_ ASM _ ("divl % 4": "= A" (CYL), "= D" (head): "0" (Block ), "1" (0 ),
"R" (hd_info [Dev]. Head ));
SEC ++;
Nsect = Current-> nr_sectors;
// Check whether some reset parameters have been set before
If (reset ){
Reset = 0;
Recalibrate = 1;
Reset_hd (current_dev );
Return;
}
If (recalibrate ){
Recalibrate = 0;
Hd_out (Dev, hd_info [current_dev]. sect, 0, 0,
Win_restore, & recal_intr );
Return;
}
// Process the request item here, read or write the corresponding command, and set the corresponding callback function
If (current-> cmd = write ){
// If it is read, send the READ command and set the interrupt callback function to write_intr.
Hd_out (Dev, nsect, SEC, Head, cyl, win_write, & write_intr );
// Check the hard disk status cyclically. If the disk is ready, send the data. After sending the data here, the do_hd_request () function has been released, when data is not sent, it is judged and executed in the callback function write_intr. If all data is sent late in the write_intr function, end_request (1) and do_hd_request () are called (). Here, end_request (1) completes the aftermath of this request item, and do_hd_request () is used to process the next request item in the request item. In this way, the queue is known to be empty.
For (I = 0; I <3000 &&! (R = inb_p (hd_status) & drq_stat); I ++)
/* Nothing */;
If (! R ){
Bad_rw_intr ();
Goto repeat;
}
Port_write (hd_data, current-& gt; buffer, 256 );
} Else if (current-> cmd = read ){
// Write operations are processed here. The processing process is similar to writing.
Hd_out (Dev, nsect, SEC, Head, cyl, win_read, & read_intr );
} Else
Panic ("unknown HD-command ");
}
Request_fn () is the initiator of request item processing, but it exits after sending the command and setting the callback function. In the future, it will be implemented through the callback function.
Static void write_intr (void)
{
If (win_result ()){
Bad_rw_intr ();
// Check the operation result. If the operation fails, call do_hd_request () again to process the current request.
Do_hd_request ();
Return;
}
// This indicates that the do_hd_request () Command has been sent successfully, and the hard disk controller has been prepared and sent out an interrupt, starting to transmit data (not sent late to continue sending ).
If (-- Current-> nr_sectors ){
Current-> sector ++;
Current-> buffer ++ = 512;
Do_hd = & write_intr;
Port_write (hd_data, current-& gt; buffer, 256 );
Return;
}
// This indicates that the operation of the current request item is completed, and the data transmission is completed, the processing of the current request item is completed, and the next request of the request item queue is started by calling do_hd_request.
End_request (1 );
Do_hd_request ();
}
Static void read_intr (void)
{
If (win_result ()){
Bad_rw_intr ();
Do_hd_request ();
Return;
}
Port_read (hd_data, current-& gt; buffer, 256 );
Current-> errors = 0;
Current-> buffer ++ = 512;
Current-> sector ++;
If (-- Current-> nr_sectors ){
Do_hd = & read_intr;
Return;
}
End_request (1 );
Do_hd_request ();
} The read process is similar.