/*
* linux/kernel/blk_dev/ll_rw.c
*
* (C) 1991 Linus Torvalds
*/

/*
* This handles all read/write requests to block devices
*/
/*
* ó豸ж/д
*/
#include <errno.h>		// ͷļϵͳиֳš(Linus minix )
#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <asm/system.h>		// ϵͳͷļû޸/жŵȵǶʽꡣ

#include "blk.h"		// 豸ͷļݽṹ豸ݽṹͺ꺯Ϣ

/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
*/
/*
* ṹкмnr ݵڴбϢ
*/
struct request request[NR_REQUEST];

/*
* used to wait on when there are no free requests
*/
/* ûпʱʱȴ */
struct task_struct *wait_for_request = NULL;

/* blk_dev_struct is:
* do_request-address
* next-request
*/
/* blk_dev_struct 豸ṹǣ(kernel/blk_drv/blk.h,23)
* do_request-address //Ӧ豸ŵָ롣
* current-request // 豸һ
*/
// ʹ豸Ϊ±꣩
struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
  {NULL, NULL},			/* no_dev */// 0 - 豸
  {NULL, NULL},			/* dev mem */// 1 - ڴ档
  {NULL, NULL},			/* dev fd */// 2 - 豸
  {NULL, NULL},			/* dev hd */// 3 - Ӳ豸
  {NULL, NULL},			/* dev ttyx */// 4 - ttyx 豸
  {NULL, NULL},			/* dev tty */// 5 - tty 豸
  {NULL, NULL}			/* dev lp */// 6 - lp ӡ豸
};

// ָĻbhָĻѾʹԼ˯ߣжϵصȴ
// ֱִнȷػѡ
static inline void
lock_buffer (struct buffer_head *bh)
{
  cli ();			// жɡ
  while (bh->b_lock)		// ѱ˯ߣֱ
    sleep_on (&bh->b_wait);
  bh->b_lock = 1;		// û
  sti ();			// жϡ
}

// ͷţĻ
static inline void
unlock_buffer (struct buffer_head *bh)
{
  if (!bh->b_lock)		// ûûбӡϢ
    printk ("ll_rw_block.c: buffer not locked\n\r");
  bh->b_lock = 0;		// ־
  wake_up (&bh->b_wait);	// ѵȴû
}

/*
* add-request adds a request to the linked list.
* It disables interrupts so that it can muck with the
* request-lists in peace.
*/
/*
* add-request()мһرжϣ
* ܰȫش */
*/
//// мdev ָ豸req ĽṹϢ
  static void
add_request (struct blk_dev_struct *dev, struct request *req)
{
  struct request *tmp;

  req->next = NULL;
  cli ();			// жϡ
  if (req->bh)
    req->bh->b_dirt = 0;	// 建ࡱ־
// dev ĵǰ(current_request)ӶΪգʾĿǰ豸ûǵ1 
// ˿ɽ豸ǰֱָָִӦ豸
  if (!(tmp = dev->current_request))
    {
      dev->current_request = req;
      sti ();			// жϡ
      (dev->request_fn) ();	// ִ豸Ӳ(3)do_hd_request()
      return;
    }
// Ŀǰ豸Ѿڵȴõ㷨λãȻ󽫵ǰ
// С
  for (; tmp->next; tmp = tmp->next)
    if ((IN_ORDER (tmp, req) ||
	 !IN_ORDER (tmp, tmp->next)) && IN_ORDER (req, tmp->next))
      break;
  req->next = tmp->next;
  tmp->next = req;
  sti ();
}

//// Сǣ豸majorrwݵĻͷָbh
static void
make_request (int major, int rw, struct buffer_head *bh)
{
  struct request *req;
  int rw_ahead;

/* WRITEA/READA is special case - it is not really needed, so if the */
/* buffer is locked, we just forget about it, else it's a normal read */
/* WRITEA/READA  - ǲǱҪģѾ*/
/* ǾͲ˳ĻִһĶ/д */
// 'READ''WRITE''A'ַӢĵAheadʾǰԤ/дݿ˼
// ָĻʹãѱʱͷԤ/д
  if (rw_ahead = (rw == READA || rw == WRITEA))
    {
      if (bh->b_lock)
	return;
      if (rw == READA)
	rw = READ;
      else
	rw = WRITE;
    }
// READ WRITE ʾں˳дʾϢ
  if (rw != READ && rw != WRITE)
    panic ("Bad block dev command, must be R/W/RA/WA");
// Ѿǰ񣨽̣ͻ˯ߣֱȷػѡ
  lock_buffer (bh);
// дһݲ࣬ǶһǸ¹ģ
// 󡣽˳
  if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate))
    {
      unlock_buffer (bh);
      return;
    }
repeat:
/* we don't allow the write-requests to fill up the queue completely:
* we want some room for reads: they take precedence. The last third
* of the requests are only for reads.
*/
/* ǲöȫдҪΪһЩռ䣺
* ȵġеĺ֮һռΪ׼ġ
*/
// ǴĩβʼġҪ󣬶ڶ󣬿ֱ
// ӶĩβʼдֻܴӶе2/3 ͷ롣
  if (rw == READ)
    req = request + NR_REQUEST;	// ڶ󣬽ָָβ
  else
    req = request + ((NR_REQUEST * 2) / 3);	// д󣬶ָָ2/3 
/* find an empty request */
/* һ */
// Ӻǰṹrequest dev ֵֶ=-1 ʱʾδռá
  while (--req >= request)
    if (req->dev < 0)
      break;
/* if none found, sleep on new requests: check for rw_ahead */
/* ûҵøô˯ߣǷǰ/д */
// ûһǿеģʱrequest ָѾԽͷ鿴˴Ƿ
// ǰ/дREADA WRITEA˴󡣷ñ˯ߣȴ
// ڳһС
  if (req < request)
    {				// ûп
      if (rw_ahead)
	{			// ǰ/д˳
	  unlock_buffer (bh);
	  return;
	}
      sleep_on (&wait_for_request);	// ñ˯ߣٲ鿴С
      goto repeat;
    }
/* fill up the request-info, and add it to the queue */
/* дϢ */
// ṹμkernel/blk_drv/blk.h,23
  req->dev = bh->b_dev;		// 豸š
  req->cmd = rw;		// (READ/WRITE)
  req->errors = 0;		// ʱĴ
  req->sector = bh->b_blocknr << 1;	// ʼ(1 =2 )
  req->nr_sectors = 2;		// д
  req->buffer = bh->b_data;	// ݻ
  req->waiting = NULL;		// ȴִɵĵط
  req->bh = bh;			// ͷָ롣
  req->next = NULL;		// ָһ
  add_request (major + blk_dev, req);	// (blk_dev[major],req)
}

//// Ͳдݿ麯
// úҪfs/buffer.c бáʵʵĶд豸request_fn()ɡ
// Ӳ̲údo_hd_request()kernel/blk_drv/hd.c,294
void
ll_rw_block (int rw, struct buffer_head *bh)
{
  unsigned int major;		// 豸ţӲ3

// 豸豸Ųڻ߸豸ĶдڣʾϢء
  if ((major = MAJOR (bh->b_dev)) >= NR_BLK_DEV ||
      !(blk_dev[major].request_fn))
    {
      printk ("Trying to read nonexistent block-device\n\r");
      return;
    }
  make_request (major, rw, bh);	// С
}

//// 豸ʼɳʼmain.c ãinit/main.c,128
// ʼ飬Ϊ(dev = -1)32 (NR_REQUEST = 32)
void
blk_dev_init (void)
{
  int i;

  for (i = 0; i < NR_REQUEST; i++)
    {
      request[i].dev = -1;
      request[i].next = NULL;
    }
}
